ci(security): task #146 lint — no GITEA/GITHUB token in tenant-writer paths #1565
Reference in New Issue
Block a user
Delete Branch "ci/146-lint-no-tenant-gitea-token"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Adds
.gitea/workflows/lint-no-tenant-gitea-token.yml— a broader-pattern CI lint companion to mc#1555's RFC#523 Layer 3 (lint-forbidden-env-keys.yml).Why
lint-forbidden-env-keys.ymlcatches QUOTED-literal hits of forbidden env names underworkspace-server/internal/. RFC#523's threat-model statement is broader: "tenant workspaces MUST NOT receive operator-scope repo-host tokens." A future writer could route the value via a variable, a struct field, or a config key and slip past the existing literal scan; this lint catches those routing patterns at PR review time.How
Co-occurrence scan: a file FIRES the lint only if it BOTH:
workspace_secrets,global_secrets,seedAllowList,/settings/secrets,envVars[,containerEnv,userData,provisionPayload,provisionContext)GITEA_TOKEN,GITEA_PAT,GITHUB_TOKEN,GITHUB_PAT,GH_TOKEN)The co-occurrence requirement is the false-positive control — a file that just logs a missing-env message won't fire.
Dry-run result on current main
17 candidate files (tenant-writer surface), 0 hits → CLEAN. Lint will pass on PR open.
Drift contract
Keys list shared (subset) with
lint-forbidden-env-keys.ymland Go source-of-truthworkspace-server/internal/handlers/workspace_provision_forbidden_env.go— if RFC#523's deny set grows, update all three.Test plan
os.Getenv("GITEA_TOKEN")next toenvVars[in a handler file) → lint FAILSworkspace_provision_forbidden_env.goadding a new quoted literal — should remain CLEAN)Refs
DO NOT MERGE — leave for 2-eye review.
core-devops 5-axis review — APPROVE.
Correctness: 179-line workflow, same co-occurrence shape as cp#202 (companion lint in CP). SURFACE_PATTERN broader (adds
provisionContext) to match molecule-core's writer shapes; FORBIDDEN_KEYS identical (GITEA_TOKEN, GITEA_PAT, GITHUB_TOKEN, GITHUB_PAT, GH_TOKEN). EXEMPT_FILES enumerates legitimate guard / silent-strip / persona-fallback files (workspace_provision_forbidden_env.go+ test,provisioner.go+ test,agent_git_identity.go,org_helpers.go,org.go,cp_provisioner.go). 0 violations in molecule-core — verified by the self-running lint on this PR being green.Readability: drift contract spelled out (this lint + cp#202 + Go SOT
workspace_provision_forbidden_env.go); per-exempt one-line justification.Architecture: no
paths:filter (required-status discipline); action pinned by full SHA;fetch-depth: 1(sub-second scan).Regex tightness: quoted-literal match (avoids comment false-positives); SURFACE_PATTERN curated against current main grep verification.
Security: catches the routing-pattern class (var/struct/config-key paths slip past literal-only scans). Open-source-template-friendly (no MOLECULE_-prefix literals).
Performance: sub-second scan.
Verdict: APPROVE.
core-security 5-axis review — APPROVE.
Threat model coverage: RFC#523 — molecule-core workspace-server is where tenant workspaces are PROVISIONED. A repo-host token leaked into a tenant's containerEnv / userData / provisionPayload = whole-platform git-host escalation. This lint catches that class at PR review time even when the token name is routed via a variable rather than a quoted literal in the writer file (because the lint requires only co-occurrence within the file, not on the same line).
Regex covers the threat model:
lint-forbidden-env-keys.yml.*_test.goexcluded from candidates.No token still slipping through this lint's scope: 0 violations on molecule-core/main (verified by the lint self-running on this PR — green). The 6 EXEMPT_FILES enumerate legitimate guard / strip / fallback paths (RFC#523 L1 SOT + tests, silent-strip denylist + tests, persona-fallback writers, CP→platform admin auth). Each exempt has a one-line justification.
Drift contract: this lint + cp#202 + Go SOT
workspace_provision_forbidden_env.go— must stay in sync, comment is explicit.Verdict: APPROVE.
core-devops re-approve at new head
23506ab7(re-triggered for transient shellcheck flake on prior head0468cee8). No code changes — empty commit only. Original 5-axis pass stands (id=4808): APPROVE.core-security re-approve at new head
23506ab7(empty re-trigger commit only, no security-relevant change). Original 5-axis pass stands (id=4809): APPROVE.core-devops: merged main into branch to pick up the
# shellcheck disable=SC2034annotations ontests/e2e/lib/peer_visibility_assert.sh+tests/e2e/test_peer_visibility_mcp_local.sh(introduced post-PR-branch in mc#1561). PR was branched before that landed → shellcheck failed against the rebased rule set even though this PR adds 0 shell files. Verified locally with the runner image: shellcheck exit=0 post-merge. Re-approving at new head.core-devops re-approve at new head
f2161bda(main-merge to pick up post-1561 shellcheck disables; no functional change to the lint workflow). Original 5-axis pass stands (id=4808). APPROVE.core-security re-approve at new head
f2161bda(main-merge to clear unrelated shellcheck red; no security-relevant change). Original 5-axis pass stands (id=4809). APPROVE.QA team APPROVE for RFC#523 CI lint workflow (lint-no-tenant-gitea-token.yml). Read-only static lint, scoped to .gitea/workflows; no runtime side-effects; gate is fail-closed by design. Reviewed at head
f2161bdad0./qa-recheck