Skip to content

chore: pin Actions SHAs, safe deps, bind dashboard identity - #60

Merged
SafetyMP merged 1 commit into
mainfrom
chore/public-repo-update-2026-09
Sep 5, 2026
Merged

chore: pin Actions SHAs, safe deps, bind dashboard identity#60
SafetyMP merged 1 commit into
mainfrom
chore/public-repo-update-2026-09

Conversation

@SafetyMP

@SafetyMP SafetyMP commented Sep 5, 2026

Copy link
Copy Markdown
Owner

Summary

  • Pin GitHub Actions to immutable commit SHAs, matching SafetyMP/corporate-site-harness#20: CodeQL v4.37.9 (cdf488f595d80d6e07e03d4674febd5ab45fa938), Scorecard v2.4.4, setup-node v7.0.0.
  • Apply safe patch/minor deps that passed verify: @hono/node-server 2.0.12, hono 4.13.7, globals 17.12.0 (lock).
  • Fix security: bind tenantId and decidedBy to authenticated identity #28: decide/appeal derive decidedBy and tenant from DASHBOARD_OPERATOR_ID / DASHBOARD_TENANT_ID (token-bound defaults). Client-supplied by / tenantId are ignored; cross-tenant attempts return 403. Still a shared static token — not a production SaaS / OIDC claim.

Supersedes Dependabot #55, #53, #52, #51, #50, #48, #47 after merge. Skips majors: vite 6→8 (#56), zod 3→4 (#54), nanoid 5→6 (#49).

Change type

  • fix — bug fix
  • chore — tooling, deps, CI

Checklist

  • ./scripts/harness/verify.sh is green locally.
  • ./scripts/harness/adversarial.sh is green locally (or N/A for docs-only).
  • New behavior is covered by a test where applicable.
  • No Express or better-sqlite3 introduced.
  • No secrets, *.db, .env, or dist/ staged.
  • Reference-architecture posture preserved (README / SECURITY scope language not weakened).
  • Company-day / demo paths keep autoApproveException default-off unless a test/CI opt-in is intentional.
  • If this introduces or reverses a decision, an ADR is added/updated in docs/adr/.
  • If the ops console UI changed materially, README screenshots were regenerated (npm run screenshots).

Test plan

  • ./scripts/harness/verify.shverify: ok (22 tests)
  • ./scripts/harness/adversarial.shadversarial: ok (AUTH still 401 without bearer)
  • test/dashboard-identity.test.ts: client by ignored; cross-tenant decide/appeal 403
  • CI verify + adversarial on this PR
  • Close superseded Dependabot PRs after merge (do not merge this PR from the agent)

Made with Cursor

Keep the public reference repo current with SHA-pinned CI (matching
corporate-site-harness#20), safe patch/minor bumps, and server-side
operator/tenant binding on decide/appeal so clients cannot spoof #28.

Co-authored-by: Cursor <cursoragent@cursor.com>
Copilot AI lite review requested due to automatic review settings September 5, 2026 17:08

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

A few workflow lines have misleading actions/checkout version comments, and the new tenant-binding introduces redundant DB reads on decide/appeal paths.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR tightens the ops dashboard mutation contract by binding decidedBy and tenantId to server-side identity (env-backed for the shared bearer token), while also applying safe dependency bumps and pinning GitHub Actions by immutable SHAs.

Changes:

  • Bind /api/exceptions/:id/decide and /api/exceptions/:id/appeal to DASHBOARD_OPERATOR_ID / DASHBOARD_TENANT_ID, ignoring client-supplied by / tenantId, and rejecting cross-tenant mutations with 403.
  • Add a focused regression test (dashboard-identity.test.ts) covering “client by ignored” and “cross-tenant denied”.
  • Pin Actions by commit SHA and update safe deps (@hono/node-server, hono, globals), plus update docs/ADR/env examples accordingly.
File summaries
File Description
apps/api/src/app.ts Derives dashboard identity from env, enforces tenant binding on decide/appeal, updates response shape.
apps/console/src/main.tsx Stops sending by in decide requests (server-derived identity).
test/dashboard-identity.test.ts Adds tests asserting server-derived decidedBy/tenant and 403 on cross-tenant operations.
.env.example Documents DASHBOARD_OPERATOR_ID / DASHBOARD_TENANT_ID defaults and intent.
SECURITY.md Documents identity binding + cross-tenant denial behavior and updated deps.
README.md Updates security posture blurb to reflect identity binding.
CONTEXT.md Notes decide/appeal identity binding in shared mode context.
docs/adr/0013-console-hitl-kill-resume.md Records the identity-binding decision in ADR.
package.json Bumps @hono/node-server and globals ranges; updates overrides to keep @hono/node-server pinned.
package-lock.json Locks updated versions (@hono/node-server 2.0.12, hono 4.13.7, globals 17.12.0).
apps/api/package.json Bumps API package deps (@hono/node-server, hono).
.github/workflows/ci.yml Pins setup-node to SHA v7.0.0; keeps checkout pinned.
.github/workflows/codeql.yml Pins CodeQL actions to v4.37.9 SHAs; keeps checkout pinned.
.github/workflows/scorecard.yml Pins Scorecard to v2.4.4 + CodeQL upload-sarif v4.37.9; keeps checkout pinned.
.github/workflows/docker.yml Keeps checkout pinned (comment updated in this PR).
.github/workflows/deploy.yml Keeps checkout pinned (comment updated in this PR).
Review details

Suppressed comments (2)

.github/workflows/ci.yml:40

  • The pinned SHA is for actions/checkout v4, but the inline comment claims v7.0.1 (which does not exist for actions/checkout). This is misleading for auditing and future maintenance—update the comment to match the actual major version being pinned.
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

apps/api/src/app.ts:171

  • This introduces an extra DB read: bindExceptionTenant() loads the exception row to check tenant, and appealException() loads the same row again. Consider moving the tenant check into appealException (or adding a core helper that accepts a preloaded exception) to avoid double-selects on this path.
    const bound = await bindExceptionTenant(company, c.req.param("id"), identity.tenantId);
    if (bound.status !== 200) return c.json({ error: bound.error }, bound.status);
    const out = await appealException(
      company,
      bound.ex.id,
      identity.operatorId,
  • Files reviewed: 15/16 changed files
  • Comments generated: 6
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread apps/api/src/app.ts
Comment on lines +145 to +149
const bound = await bindExceptionTenant(company, c.req.param("id"), identity.tenantId);
if (bound.status !== 200) return c.json({ error: bound.error }, bound.status);
const out = await decideException(
company,
c.req.param("id"),
bound.ex.id,
Comment thread .github/workflows/ci.yml
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
language: [javascript-typescript]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v4
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
@SafetyMP
SafetyMP merged commit f0f86a3 into main Sep 5, 2026
6 checks passed
@SafetyMP
SafetyMP deleted the chore/public-repo-update-2026-09 branch September 5, 2026 17:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security: bind tenantId and decidedBy to authenticated identity

2 participants