Audit failed at 2026-09-25T10:02Z. Run · Transcript
- A domain returned
FAIL. audit-application.md opened with VERDICT: FAIL — read that domain's section first. A domain's own verdict outranks the merged one.
Lines that decided this verdict
Lifted out of the fragments so truncation cannot cut them. Each domain's full section follows for as far as the body reaches.
audit-supply-chain.md: VERDICT: PASS
audit-ci-secrets.md: VERDICT: PASS
audit-application.md: VERDICT: FAIL
audit-hosted.md: VERDICT: PASS
audit-application.md: - WARNING (see qualitative findings) — tsip="$(ts ip -4 2>/dev/null | head -1 || true)" is a literal instance of the banned shape on Tailscale CLI output [macos] install-macos.sh:902; [linux] install-linux.sh:1131
audit-application.md: - WARNING — burrowToken travels in a URL query string on every Burrow relay connection: ?${WS_TOKEN_PARAM}=${encodeURIComponent(this.#enrollment.burrowToken)} (/home/runner/work/dormouse/dormouse/lib/src/remote/burrow/burrow-runtime.ts:771), validated from c.req.query(WS_TOKEN_PARAM) (/home/runner/work/dormouse/dormouse/relay/src/app.ts:1296). docs/specs/relay.md:327 justifies query-param WS auth with "browsers cannot set WebSocket headers" — true for /ws/client, but the `/ws/b
audit-application.md: - WARNING — head -1 on Tailscale CLI output, at a site the rationale's own scoping says the rule binds. tsip="$(ts ip -4 2>/dev/null | head -1 || true)" at /home/runner/work/dormouse/dormouse/deploy/local/install-macos.sh:902 and /home/runner/work/dormouse/dormouse/deploy/local/install-linux.sh:1131 is an inline command substitution whose value drives a manage verify decision, which is exactly the shape docs/specs/security-remote.md:197 names and `docs/specs/security-remote.rationa
audit-application.md: #### WARNINGs (7, none a boundary crossing)
Security audit
Supply chain
VERDICT: PASS
FAIL IF results
-
FAIL IF node website/scripts/generate-deps.js changes the three disclosure JSON files after pnpm install --frozen-lockfile. PASS. Ran pnpm install --frozen-lockfile (lockfile up to date, no changes), then node website/scripts/generate-deps.js (wrote 66 npm deps, 12 direct + 478 transitive cargo deps, 1 bundled runtime). git status --porcelain website/src/data/ and git diff website/src/data/ are both empty — no diff produced.
-
FAIL IF .github/workflows/ci.yml stops running the generator under the --frozen-lockfile precondition or stops failing on a diff. PASS. ci.yml lines 24-25 run pnpm install --frozen-lockfile; the "Dependency disclosure is current" step (lines 39-46) runs node website/scripts/generate-deps.js then git diff --quiet -- website/src/data/, exit 1 on a diff.
-
FAIL IF the disclosure omits a shipped workspace's graph or excludes a shipped package. PASS. Derived independently from pnpm-workspace.yaml's 11 packages against each package.json's declared name: productDependencyFilters = dor, dormouse (vscode-ext), dormouse-standalone, dormouse-lib (lib), dormouse-sidecar (standalone/sidecar), relay (6 roots); excludedWorkspacePackages = canopy, dormouse-website (website), dormouse-hosted (hosted) (3 exclusions, each installs no artifact — canopy is Storybook-only, website runs in a visitor's browser, hosted runs on Workers/browser only). The remaining 2 packages, dor-lib-common and remote-lib-common, are workspace edges reached via runtime dependencies (not devDependencies) from roots: dor-lib-common from dor and lib's package.json dependencies; remote-lib-common from lib and relay's dependencies. All 11 workspace packages accounted for by root, exclusion, or reachable edge — matches what assertWorkspaceCoverage in website/scripts/dependency-workspaces.js enforces at generation time (verified it throws on unclassified/duplicate/stale names and on a reachable exclusion; website/scripts/dependency-workspaces.test.js covers these cases).
-
FAIL IF root package.json is missing devEngines.runtime.version, or its value is not an exact MAJOR.MINOR.PATCH. PASS. package.json -> devEngines.runtime.version = "24.18.0", matches ^\d+\.\d+\.\d+$.
-
FAIL IF standalone/src-tauri/build.rs no longer runs --version on the bundled binary and fails the build on mismatch, or the check is skipped for a release-matrix configuration other than the permitted host!=target skip. PASS. verify_node_version (build.rs:191-227) runs node_source --version, compares trimmed output against read_pinned_node_version's parse of devEngines.runtime.version, and returns Err (failing the build via .expect(...) in bundle_node_runtime) on mismatch. The only skip is host != target (build.rs:197-205), which only warns and returns Ok. .github/workflows/release.yml's build-standalone matrix (lines 26-36) has exactly three entries — ubuntu-22.04/x86_64-unknown-linux-gnu, macos-latest/aarch64-apple-darwin, windows-latest/x86_64-pc-windows-msvc — each platform runner native to its own target, so host == target for every entry the release matrix builds and the skip path is never exercised in CI today.
-
FAIL IF the build-standalone job does not install the pinned runtime via node-version-file: package.json, or root package.json gains a volta.node or engines.node field. PASS. release.yml lines 46-48 use actions/setup-node with node-version-file: package.json. package.json has no volta key and no engines key (grepped both; only devEngines.runtime present).
-
FAIL IF pnpm-workspace.yaml is missing minimumReleaseAge: 1440. PASS. pnpm-workspace.yaml:44 sets minimumReleaseAge: 1440 (1440 minutes = 24 hours).
-
FAIL IF .github/renovate.json is missing npm or cargo from enabledManagers, or is missing minimumReleaseAge package rules for those managers. PASS. enabledManagers = ["github-actions", "npm", "cargo"]. packageRules includes three rules matching matchManagers: ["npm", "cargo"] with matchUpdateTypes patch/minor/major set to minimumReleaseAge "1 day"/"3 days"/"14 days" respectively.
-
FAIL IF .github/renovate.json has no vulnerabilityAlerts block, or that block does not explicitly set minimumReleaseAge. PASS. vulnerabilityAlerts block present with "minimumReleaseAge": "1 day" set explicitly (and a comment explaining why omitting it would silently drop the cooldown to null).
-
FAIL IF secret scanning or push protection is disabled, or Dependabot alerts are off. PASS, all three clauses. GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse --jq .security_and_analysis (200) -> secret_scanning.status: "enabled"; secret_scanning_push_protection.status: "enabled". GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/vulnerability-alerts -i -> HTTP/2.0 204 No Content (Dependabot alerts on). Note (not part of this FAIL IF): dependabot_security_updates.status is "disabled" — automatic Dependabot PRs are off, but the spec does not require them; Renovate's vulnerabilityAlerts block (checked above) is the path this repo uses instead.
Qualitative findings
Scope worked: lib/package.json added ws (^8.21.3) to its runtime dependencies (plus @types/ws, playwright-core to devDependencies) since the last successful audit (comparing head commit 8836c754 from the 2026-09-24 09:19 UTC PASS run against current main, via gh api repos/diffplug/dormouse/compare/...). This is a genuine new production dependency on a disclosed root (dormouse-lib). Verified it is legitimately used (lib/src/host/agent-browser-host.ts, lib/src/host/browser-viewer.ts, lib/src/host/browser-host.ts — Node-side host modules bundled into both hosts) and is already correctly disclosed: the FAIL-IF-1 regeneration above produced no diff, confirming dependencies-npm.json already reflects it. No lockfile change was needed since ws was already resolved elsewhere in the graph. This is exactly the class of change the CI regeneration gate (FAIL IF 2) exists to catch per the rationale's ws/hono history, and it passed cleanly this time. INFO, not a finding.
Non-registry lockfile resolutions: grepped pnpm-lock.yaml for tarball:/http(s):// resolutions outside the npm registry. Found three kinds: (1) @diffplug/xterm-addon-webgl-sdf, a GitHub-release tarball, is canopy's dependency only — canopy is in excludedWorkspacePackages (Storybook-only lab, docs/specs/webgl-text.md documents the fork pipeline) and is not reachable from any product root (confirmed under check 3), so it correctly never reaches the disclosure or a user's machine. (2) pgstencil / @pgstencil/auth, resolved via file:vendor/*.tgz per pnpm-workspace.yaml's overrides, belong to hosted/dormouse-hosted, which is also excluded — pgstencil provenance is the hosted domain's scope (docs/specs/security-hosted.md), not this one. (3) nodejs.org/unofficial-builds.nodejs.org tarball URLs under the root node: runtime:24.18.0 devEngines entry are pnpm's own runtime-provisioning URLs for the pinned Node version already covered by the Bundled Runtime checks above. None of the three represent an undisclosed package reaching a user's machine. INFO.
Install scripts in production dependencies: pnpm-workspace.yaml's allowBuilds map permits native builds for workerd, @swc/core, esbuild, node-pty, and sharp, and blocks them for cpu-features, protobufjs, ssh2, @vscode/vsce-sign, and keytar. Traced each allowed package with pnpm why against the six product roots' direct dependencies (not devDependencies): only node-pty is a direct runtime dependency of a shipped root (dormouse / vscode-ext and dormouse-sidecar), which is expected (native PTY addon) and already disclosed. esbuild, @swc/core, and workerd only reach dormouse-hosted / build tooling (wrangler, storybook, argos-ci), which is excluded from the shipped graph. sharp is pulled in as a dependencies-declared transitive of ascii-splash under dormouse-website (excluded — browser-only, and sharp's native binary cannot run in a browser regardless, so it is a build-time-only artifact) and otherwise only as devDependencies of dormouse-hosted/dormouse-lib tooling. No allowed-build package reaches a shipped root through an undisclosed path. INFO.
Any package reachable but undisclosed: none found. The root-completeness derivation (check 3) accounts for all 11 workspace packages, and the clean generate-deps.js diff (check 1) confirms the generated disclosure matches what the roots currently resolve to.
CI and secrets
VERDICT: PASS
FAIL IF results
- FAIL IF
pull_request_target appears outside tend-*.yaml (security-ci.md "GitHub Actions Policies"): PASS. Grep of .github/workflows/** shows pull_request_target only as an on: trigger in tend-review.yaml (agent-managed, exempt) and as a code comment in hosted-preview.yml:75 ("Never expose deployment credentials to fork code or pull_request_target"), which is not a trigger.
- FAIL IF a non-agent-managed workflow has effective write permissions other than
id-token: write/attestations: write or the security-audit job's actions: write (security-ci.md "GitHub Actions Policies"): PASS. argos.yml, ci.yml, hosted-preview.yml, hosted-production.yml declare only workflow-level contents: read (job changes in hosted-preview.yml additionally scopes pull-requests: read, a read permission). release.yml is workflow-level contents: read; its build-standalone/build-vscode jobs add id-token: write+attestations: write (the documented exception, gated on the release-attest environment admitting only admin-gated v* tags), its security-audit job adds only actions: write (the documented exception), and publish-vscode has no job-level permissions block, so it inherits workflow-level contents: read.
- FAIL IF every
uses: ref in a non-tend-*.yaml workflow is not pinned by commit SHA: PASS. Scanned every uses: line in argos.yml, ci.yml, hosted-preview.yml, hosted-production.yml, release.yml, security-audit.yaml, workflow-audit.yaml — every ref is a 40-hex-character commit SHA with a version comment. tend-*.yaml files use tag pins (max-sixty/tend/claude@0.3.2, actions/checkout@v7, astral-sh/setup-uv@v10.2.0), consistent with the documented exemption.
- FAIL IF an agent-managed workflow job's effective
GITHUB_TOKEN permissions exceed contents: write, pull-requests: write, issues: write, id-token: write, actions: read, or any read scope: PASS. Checked every permissions: block (workflow- and job-level) in all tend-*.yaml, workflow-audit.yaml, and security-audit.yaml — every declared scope is within the allowed set (contents: write, pull-requests: write/read, issues: write, actions: read, id-token: write).
- FAIL IF
default_workflow_permissions is not read or can_approve_pull_request_reviews is not false: PASS. GET repos/diffplug/dormouse/actions/permissions/workflow returns {"default_workflow_permissions":"read","can_approve_pull_request_reviews":false}.
- FAIL IF private vulnerability reporting is disabled: PASS.
GET repos/diffplug/dormouse/private-vulnerability-reporting returns {"enabled":true}.
- FAIL IF either admin-gating ruleset is missing or weakened (security-ci.md "Automated Maintainer (tend)"): PASS, both clauses.
GET .../rulesets/16757376 ("Merge access"): target: branch, conditions.ref_name.include: ["~DEFAULT_BRANCH"], rules: [update, deletion, creation], bypass_actors: [{actor_id:5, actor_type:RepositoryRole, bypass_mode:exempt}] — matches spec exactly (target, all three blocked operations, sole admin bypass actor). GET .../rulesets/16757382 ("Tag operations"): target: tag, conditions.ref_name.include: ["~ALL"], rules: [creation, update], same sole admin bypass actor — matches spec exactly.
- FAIL IF
dormouse-bot holds maintain or admin: PASS. GET repos/diffplug/dormouse/collaborators/dormouse-bot/permission returns permission: "write", role_name: "write" — neither maintain nor admin.
- FAIL IF any GitHub environment except
hosted-preview admits a ref not admin-gated by Tag operations/Merge access: PASS for every non-hosted-preview environment. Enumerated all 7 environments (GET .../environments) and each one's deployment-branch-policies: hosted-production admits only main (branch, covered by "Merge access" which blocks all non-admin update/creation/deletion on ~DEFAULT_BRANCH); hosted-release-tag admits only main (same); release-attest admits only tag pattern v* (covered by "Tag operations", ~ALL tags, admin-only creation/update); security-audit admits main and tag v* (both covered); tend admits only main (covered); vscode-extension-publish admits only tag v* (covered). hosted-preview (the named exception) admits main and refs/pull/*/merge — checked instead against "Hosted Deployments" below.
- FAIL IF a Hosted environment lacks branch restrictions, required reviewers, or disabled administrator bypass (security-ci.md "Hosted Deployments"): PASS, all three environments.
hosted-preview: admits main + refs/pull/*/merge, required_reviewers = [nedtwigg, edgartwigg], prevent_self_review: false (self-review is explicitly allowed by spec), can_admins_bypass: false. hosted-production: admits only main, same two reviewers, can_admins_bypass: false. hosted-release-tag: admits only main, same two reviewers, can_admins_bypass: false.
- FAIL IF Hosted credentials appear at repository/org scope, or production credentials appear in
hosted-preview: PASS. Repo-level secrets are exactly ARGOS_TOKEN, CHROMATIC_PROJECT_TOKEN (0 Hosted-related names); org-level secrets: 0 entries. hosted-preview's environment secrets (CLOUDFLARE_API_TOKEN, NEON_API_KEY, PREVIEW_AUTH_SECRET) are distinct, environment-scoped GitHub secret objects from hosted-production's own CLOUDFLARE_API_TOKEN — GitHub environment secrets are never shared across environments by name, so no production secret value can be present in hosted-preview through GitHub's placement mechanism; this is the limit of what "inspect GitHub secret placement" can determine (the underlying token's actual Cloudflare/Neon privilege scope is not GitHub-readable).
- FAIL IF
HOSTED_TAG_TOKEN appears outside hosted-release-tag, or that environment is used by a job other than tag in hosted-production.yml: PASS. HOSTED_TAG_TOKEN does not appear in any repo secret, org secret, or any other environment's secret listing (in fact hosted-release-tag's own secret listing is currently empty — 0 entries — a provisioning gap, not a placement violation). grep of .github/workflows/** shows hosted-release-tag referenced only once, as the environment: of the tag job in hosted-production.yml, and HOSTED_TAG_TOKEN referenced only in that same job.
- FAIL IF a Hosted preview deploy accepts a fork or a failing verification, preview cleanup checks out a PR ref rather than
main, or a Hosted production tag can run before live verification succeeds: PASS. hosted-preview.yml's deploy job requires needs: verify and its if: excludes forks (github.event.pull_request.head.repo.full_name == github.repository); cleanup checks out refs/heads/main explicitly, not the PR ref. hosted-production.yml's tag job has needs: deploy, and deploy itself runs the live smoke check (production.mjs smoke) as its last step before finishing, so tag cannot start until that verification succeeds.
- FAIL IF
.config/tend.yaml does not set merge: restricted, or any tend-*.yaml passes another merge:: PASS. .config/tend.yaml sets merge: restricted; every tend-*.yaml that embeds a merge: key (tend-ci-fix.yaml, tend-mention.yaml, tend-nightly.yaml, tend-notifications.yaml, tend-review-runs.yaml, tend-review.yaml, tend-triage.yaml, tend-weekly.yaml) passes merge: restricted, none other.
- FAIL IF
CHROMATIC_PROJECT_TOKEN or ARGOS_TOKEN is missing from secrets.allowed in .config/tend.yaml: PASS. .config/tend.yaml's secrets.allowed lists exactly CHROMATIC_PROJECT_TOKEN and ARGOS_TOKEN.
- FAIL IF Renovate's
github-actions manager can update .github/workflows/tend-*.yaml: PASS. .github/renovate.json packageRules has a rule with matchManagers: ["github-actions"], matchFileNames: [".github/workflows/tend-*.yaml"], enabled: false.
- FAIL IF any
tend-*.yaml pins max-sixty/tend below 0.1.19: PASS. Every tend-*.yaml's max-sixty/tend/claude@0.3.2 (>= 0.1.19).
- FAIL IF any
tend-*.yaml workflow uses an unpinned action reference: PASS. All uses: refs in tend-*.yaml are tag pins with an explicit version (actions/checkout@v7, astral-sh/setup-uv@v10.2.0, max-sixty/tend/claude@0.3.2) — none is @main or bare/unversioned.
- FAIL IF
.github/workflows/workflow-audit.yaml starts deriving its lower bound from anything the pusher controls: PASS. SINCE is read from gh api .../actions/workflows/workflow-audit.yaml/runs?status=success&per_page=1 --jq '.workflow_runs[0].created_at' (server-set), falling back to 25 hours ago only when no prior successful run exists; no pusher-controlled timestamp (e.g. committer date, --since) is used.
- FAIL IF
.github/audit/ or .vscode/ is outside any consumer of workflow-audit.yaml's diff window: PASS. WINDOW=(.github/workflows/ .config/tend.yaml .github/audit/ .vscode/) is the single definition; WINDOW_NON_WORKFLOW=("${WINDOW[@]:1}") is derived from it (not hand-duplicated); COMMITS (git log … -- "${WINDOW[@]}"), own_changes(), is_clean_merge(), is_renovate_pin_bump()'s refusal, and is_tend_regen()'s refusal all reference WINDOW/WINDOW_NON_WORKFLOW rather than a separately hand-maintained list.
- FAIL IF
.github/workflows/workflow-audit.yaml is missing, disabled, or has not produced a successful run in the last 48 hours: PASS. GET .../actions/workflows/workflow-audit.yaml shows state: active; the 5 most recent runs are all conclusion: success, most recently 2026-09-24T12:41:20Z (within 48h of the audit's run time, 2026-09-25).
- FAIL IF
vscode-extension-publish lacks nonempty required reviewers, prevent_self_review: true, or can_admins_bypass: false: PASS. Environment API shows required_reviewers = [nedtwigg, edgartwigg] (nonempty), prevent_self_review: true, can_admins_bypass: false.
- FAIL IF
release.yml is missing the vscode-extension-publish environment on the VS Code publish job, or VSCE_PAT/OVSX_PAT are referenced from a job not bound to that environment: PASS. publish-vscode job declares environment: {name: vscode-extension-publish}. Repo-wide grep shows VSCE_PAT/OVSX_PAT referenced only at release.yml:347 and :359, both inside that same job.
- FAIL IF
release.yml uses production desktop signing secrets in CI, or stops generating an ephemeral Tauri updater key for unsigned CI artifacts: PASS. build-standalone runs "Generate ephemeral Tauri updater key" (tauri signer generate --ci --write-keys … --force) and exports it as TAURI_SIGNING_PRIVATE_KEY; repo-wide grep of .github/workflows/ finds no reference to APPLE_SIGN_PASS, EV_SIGN_PIN, or a non-ephemeral TAURI_SIGNING_PRIVATE_KEY.
- FAIL IF
scripts/sign-and-deploy.sh stops verifying GitHub artifact attestations, stops verifying SHA-256 manifests, or stops using PIV-backed Windows signing: PASS. verify_downloaded_artifact() calls gh attestation verify with --cert-identity/--cert-oidc-issuer/--source-ref/--source-digest, and check_sha256_manifest() runs sha256sum -c/shasum -a 256 -c; sign_windows() calls jsign --storetype PIV.
- FAIL IF
TAURI_SIGNING_PRIVATE_KEY is passed on a command line, or EV_SIGN_PIN is passed literally to jsign --storepass: PASS. TAURI_SIGNING_PRIVATE_KEY is exported as an env var before tauri signer sign "$bundle" (never appears as a flag value); jsign --storepass env:EV_SIGN_PIN passes the literal string env:EV_SIGN_PIN (an indirection token jsign itself resolves from its environment), not the PIN value. APPLE_SIGN_PASS is passed as xcrun notarytool --password "$APPLE_SIGN_PASS" (argv) — this is the documented, accepted "Known gap" in security-ci.md, not a FAIL IF violation.
- FAIL IF
.github/workflows/security-audit.yaml is missing/disabled, or the gh workflow run dispatch / gh run watch --exit-status / publish-vscode's needs: edge is gone (security-audit.md release-gate check): PASS. GET .../actions/workflows/security-audit.yaml shows state: active. release.yml's security-audit job runs gh workflow run "$workflow" … --ref "$tag" then gh run watch "$run_id" … --exit-status; publish-vscode declares needs: [build-standalone, build-vscode, security-audit].
- FAIL IF a
docs/specs/security*.md spec is in no domain's scope, in two, or a scope names a nonexistent file (security-audit.md "Domains"): PASS. Manually cross-checked each domain file's **Scope** bullet list against the 7 non-rationale docs/specs/security*.md files: ci-and-secrets claims security.md, security-ci.md, security-audit.md; application-security claims security-local.md, security-remote.md; hosted claims security-hosted.md; supply-chain claims security-supply-chain.md — exactly one claimant each, no orphan, no dangling path. node scripts/spec-lint.mjs (which mechanically enforces this as "check 16") independently confirms: spec-lint: OK (35 specs, 71 files checked).
- FAIL IF the audit stops fanning out to dedicated
application-security/hosted subagents, or either scope is merged into a context also carrying another domain: PASS. .github/audit/orchestrator.md §1 spawns exactly supply-chain, ci-and-secrets, application-security, hosted as four separate subagent_type Task calls in one message; each domain file (.github/audit/*.md) has its own single-domain **Scope** block, none combined.
- FAIL IF
application-security/hosted does not run on a stronger model than the mechanical domains, in both security-audit.yaml's claude_args and scripts/security-audit-local.sh: PASS. security-audit.yaml's claude_args sets --model sonnet as the session default and the --agents JSON overrides "model":"opus" for exactly application-security and hosted. scripts/security-audit-local.sh's run_domain() sets model_args="--model sonnet" by default and overrides to --model opus for application-security|hosted via the same case statement.
- FAIL IF
.github/audit/ is missing a prompt file the workflow names, or security-audit-local.sh stops running from those same files: PASS. All six files (_preamble.md, orchestrator.md, supply-chain.md, ci-and-secrets.md, application-security.md, hosted.md) exist; security-audit-local.sh loops over exactly this set at startup (for f in _preamble orchestrator supply-chain ci-and-secrets application-security hosted) and errors out if any is missing, then run_domain() reads _preamble.md + $domain.md via cat, matching the workflow's --agents prompt pointers.
- FAIL IF tend regeneration materializes anything except regular
.config/tend.yaml and workflow YAML blobs from the audited commit: PASS. is_tend_regen() in workflow-audit.yaml (lines 268-273) walks git ls-tree -r "$sha" -- .config/tend.yaml .github/workflows/ and returns failure (1) unless every entry's mode is 100644 or 100755 (rejecting symlinks/submodules) and every path is exactly .config/tend.yaml or matches .github/workflows/[^/]+\.ya?ml$.
- FAIL IF the orchestrator prompt stops requiring a non-turn-ending wait — a Bash
until loop over the fragments' sentinels, breaking on its own sub-cap, re-issued under a bounded 32-minute deadline persisted to a file: PASS. .github/audit/orchestrator.md §2 defines DEADLINE_FILE="$RUNNER_TEMP/audit-deadline" seeded to now + 1920 (32 min) only if absent, an until … finished … loop over all four fragment sentinels with CALL_END breaking at 540s so the call always prints an answer, and explicit instructions to re-issue the block verbatim (reading back the same DEADLINE_FILE) on STILL WAITING. security-audit.yaml's BASH_DEFAULT_TIMEOUT_MS: "600000" sets the cap this loop assumes, and timeout-minutes: 40 on the job exceeds the 32-minute wait deadline plus setup overhead.
- FAIL IF the prompt permits ending the turn without
audit-report.md: PASS. .github/audit/orchestrator.md §4 states verbatim: "Never end your turn while audit-report.md does not exist... If you have nothing left to wait on, merge §3 with whatever fragments exist and let its markers say the rest."
- FAIL IF a domain prompt lets findings be held for a write-up at the end, lets a domain that delegates end its turn or background its wait loop, or the wait/merge/verdict treats existence rather than the sentinel as reported: PASS.
.github/audit/_preamble.md requires fragments to be opened before the first check and appended to "as you determine them — never buffered... for one write-up at the end", and requires any delegating domain to "block for your delegates — never end your turn to wait", explicitly forbidding run_in_background. Both the orchestrator's wait loop (finished()) and merge step (emit()) test for the literal <!-- END OF REPORT --> sentinel via [ -s "$1" ] && [ "$(... | tail -n1)" = "<!-- END OF REPORT -->" ], not mere file existence.
- FAIL IF the orchestrator can report
PASS while a subagent left no report fragment, nor FAIL unless some domain actually returned one: PASS. .github/audit/orchestrator.md §4: "write no status file at all" whenever any domain is missing/empty/unreadable/unsentineled, and "PASS requires all four domains to pass"; FAIL requires "any subagent returned FAIL" — a real domain verdict. security-audit.yaml's reporting step independently re-derives this from the fragments themselves (MISSING_FRAGMENTS, UNFINISHED, UNREADABLE_VERDICTS, INCONCLUSIVE_DOMAINS loops, none gated on $STATUS) rather than trusting the orchestrator's own audit-status.txt, so a prompt failure alone cannot produce a false PASS.
- FAIL IF the
Redact secrets from agent output step is removed, stops covering any sink that is later published, or stops failing closed: PASS. The step is if: always(), runs before the artifact-upload and reporting steps, redacts AUDIT_PAT and CLAUDE_CODE_OAUTH_TOKEN from $TRANSCRIPT, audit-report.md, and every file in $AUDIT_FRAGMENTS (all four domain fragments — the identical set named in the job-level env: and consumed by the reporting step's guard loops and the artifact upload's path:), and on any Node error runs rm -f "$TRANSCRIPT" audit-report.md $AUDIT_FRAGMENTS; exit 1 — deleting rather than shipping an unredacted sink.
- FAIL IF the reporting step writes issue prose per combination of conditions rather than one note per condition that holds: PASS. The
NOTES block in the "Surface result" step is five independent if [ -n "${VAR:-}" ] blocks (DISSENTING, MISSING_FRAGMENTS, UNREADABLE_VERDICTS, UNFINISHED, INCONCLUSIVE_DOMAINS) plus one for FILE_STATUS = MISSING, each appending its own line independently — no combinatorial branching.
- FAIL IF either fragment guard is gated on the status at all: PASS. Both
for f in $AUDIT_FRAGMENTS loops (the missing-fragment check and the sentinel/verdict-line check) run unconditionally, before the STATUS escalation block; the code comments explicitly note "Both loops now run UNCONDITIONALLY."
- FAIL IF the reporting step accepts any domain verdict other than exact
VERDICT: PASS as passing, fails to recognize a VERDICT: FAIL prefix as dissent, ignores an inconclusive domain, accepts a fragment with no completion sentinel as finished, or accepts status text other than literal PASS/FAIL: PASS. The verdict case matches 'VERDICT: FAIL'* (prefix, so "FAIL" plus explanation still dissents) into DISSENTING, only the exact string 'VERDICT: PASS' as passing, 'VERDICT: INCONCLUSIVE' into INCONCLUSIVE_DOMAINS, and everything else into UNREADABLE_VERDICTS; the sentinel test (tail -n1 after stripping blank lines) is a separate, unconditional check that flags UNFINISHED regardless of the verdict line. FILE_STATUS is parsed with case "${FILE_STATUS:-}" in PASS|FAIL) ;; *) FILE_STATUS=MISSING ;; esac — only the literal strings pass through.
- FAIL IF the step that verifies
AUDIT_PAT is provisioned before the audit runs is removed or bypassed: PASS. security-audit.yaml's "Verify AUDIT_PAT is provisioned" step runs after checkout/setup-node/install and before the "Audit against the security specs" step, checks [ -n "$AUDIT_PAT" ], and on failure writes audit-report.md/audit-status.txt and exit 1 (job fails, no audit step runs).
Qualitative findings
Truncated to fit: the full body is 336081 characters. The untruncated audit-report.md is in this run's audit-transcript artifact (download).
Audit failed at 2026-09-25T10:02Z. Run · Transcript
FAIL. audit-application.md opened withVERDICT: FAIL— read that domain's section first. A domain's own verdict outranks the merged one.Lines that decided this verdict
Lifted out of the fragments so truncation cannot cut them. Each domain's full section follows for as far as the body reaches.
audit-supply-chain.md: VERDICT: PASSaudit-ci-secrets.md: VERDICT: PASSaudit-application.md: VERDICT: FAILaudit-hosted.md: VERDICT: PASSaudit-application.md: - WARNING (see qualitative findings) —tsip="$(ts ip -4 2>/dev/null | head -1 || true)"is a literal instance of the banned shape on Tailscale CLI output [macos] install-macos.sh:902; [linux] install-linux.sh:1131audit-application.md: - WARNING —burrowTokentravels in a URL query string on every Burrow relay connection:?${WS_TOKEN_PARAM}=${encodeURIComponent(this.#enrollment.burrowToken)}(/home/runner/work/dormouse/dormouse/lib/src/remote/burrow/burrow-runtime.ts:771), validated fromc.req.query(WS_TOKEN_PARAM)(/home/runner/work/dormouse/dormouse/relay/src/app.ts:1296).docs/specs/relay.md:327justifies query-param WS auth with "browsers cannot set WebSocket headers" — true for/ws/client, but the `/ws/baudit-application.md: - WARNING —head -1on Tailscale CLI output, at a site the rationale's own scoping says the rule binds.tsip="$(ts ip -4 2>/dev/null | head -1 || true)"at /home/runner/work/dormouse/dormouse/deploy/local/install-macos.sh:902 and /home/runner/work/dormouse/dormouse/deploy/local/install-linux.sh:1131 is an inline command substitution whose value drives amanage verifydecision, which is exactly the shapedocs/specs/security-remote.md:197names and `docs/specs/security-remote.rationaaudit-application.md: #### WARNINGs (7, none a boundary crossing)Security audit
Supply chain
VERDICT: PASS
FAIL IF results
FAIL IF
node website/scripts/generate-deps.jschanges the three disclosure JSON files afterpnpm install --frozen-lockfile. PASS. Ranpnpm install --frozen-lockfile(lockfile up to date, no changes), thennode website/scripts/generate-deps.js(wrote 66 npm deps, 12 direct + 478 transitive cargo deps, 1 bundled runtime).git status --porcelain website/src/data/andgit diff website/src/data/are both empty — no diff produced.FAIL IF
.github/workflows/ci.ymlstops running the generator under the--frozen-lockfileprecondition or stops failing on a diff. PASS.ci.ymllines 24-25 runpnpm install --frozen-lockfile; the "Dependency disclosure is current" step (lines 39-46) runsnode website/scripts/generate-deps.jsthengit diff --quiet -- website/src/data/,exit 1on a diff.FAIL IF the disclosure omits a shipped workspace's graph or excludes a shipped package. PASS. Derived independently from
pnpm-workspace.yaml's 11 packages against each package.json's declaredname:productDependencyFilters= dor, dormouse (vscode-ext), dormouse-standalone, dormouse-lib (lib), dormouse-sidecar (standalone/sidecar), relay (6 roots);excludedWorkspacePackages= canopy, dormouse-website (website), dormouse-hosted (hosted) (3 exclusions, each installs no artifact — canopy is Storybook-only, website runs in a visitor's browser, hosted runs on Workers/browser only). The remaining 2 packages, dor-lib-common and remote-lib-common, are workspace edges reached via runtimedependencies(notdevDependencies) from roots:dor-lib-commonfromdorandlib's package.jsondependencies;remote-lib-commonfromlibandrelay'sdependencies. All 11 workspace packages accounted for by root, exclusion, or reachable edge — matches whatassertWorkspaceCoverageinwebsite/scripts/dependency-workspaces.jsenforces at generation time (verified it throws on unclassified/duplicate/stale names and on a reachable exclusion;website/scripts/dependency-workspaces.test.jscovers these cases).FAIL IF root
package.jsonis missingdevEngines.runtime.version, or its value is not an exactMAJOR.MINOR.PATCH. PASS.package.json->devEngines.runtime.version="24.18.0", matches^\d+\.\d+\.\d+$.FAIL IF
standalone/src-tauri/build.rsno longer runs--versionon the bundled binary and fails the build on mismatch, or the check is skipped for a release-matrix configuration other than the permitted host!=target skip. PASS.verify_node_version(build.rs:191-227) runsnode_source --version, compares trimmed output againstread_pinned_node_version's parse ofdevEngines.runtime.version, and returnsErr(failing the build via.expect(...)inbundle_node_runtime) on mismatch. The only skip ishost != target(build.rs:197-205), which only warns and returnsOk..github/workflows/release.yml'sbuild-standalonematrix (lines 26-36) has exactly three entries —ubuntu-22.04/x86_64-unknown-linux-gnu,macos-latest/aarch64-apple-darwin,windows-latest/x86_64-pc-windows-msvc— each platform runner native to its own target, sohost == targetfor every entry the release matrix builds and the skip path is never exercised in CI today.FAIL IF the
build-standalonejob does not install the pinned runtime vianode-version-file: package.json, or rootpackage.jsongains avolta.nodeorengines.nodefield. PASS.release.ymllines 46-48 useactions/setup-nodewithnode-version-file: package.json.package.jsonhas novoltakey and noengineskey (grepped both; onlydevEngines.runtimepresent).FAIL IF
pnpm-workspace.yamlis missingminimumReleaseAge: 1440. PASS.pnpm-workspace.yaml:44setsminimumReleaseAge: 1440(1440 minutes = 24 hours).FAIL IF
.github/renovate.jsonis missingnpmorcargofromenabledManagers, or is missingminimumReleaseAgepackage rules for those managers. PASS.enabledManagers=["github-actions", "npm", "cargo"].packageRulesincludes three rules matchingmatchManagers: ["npm", "cargo"]withmatchUpdateTypespatch/minor/major set tominimumReleaseAge"1 day"/"3 days"/"14 days" respectively.FAIL IF
.github/renovate.jsonhas novulnerabilityAlertsblock, or that block does not explicitly setminimumReleaseAge. PASS.vulnerabilityAlertsblock present with"minimumReleaseAge": "1 day"set explicitly (and a comment explaining why omitting it would silently drop the cooldown to null).FAIL IF secret scanning or push protection is disabled, or Dependabot alerts are off. PASS, all three clauses.
GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse --jq .security_and_analysis(200) ->secret_scanning.status: "enabled";secret_scanning_push_protection.status: "enabled".GH_TOKEN=$AUDIT_PAT gh api repos/diffplug/dormouse/vulnerability-alerts -i->HTTP/2.0 204 No Content(Dependabot alerts on). Note (not part of this FAIL IF):dependabot_security_updates.statusis"disabled"— automatic Dependabot PRs are off, but the spec does not require them; Renovate'svulnerabilityAlertsblock (checked above) is the path this repo uses instead.Qualitative findings
Scope worked:
lib/package.jsonaddedws(^8.21.3) to its runtimedependencies(plus@types/ws,playwright-coreto devDependencies) since the last successful audit (comparing head commit8836c754from the 2026-09-24 09:19 UTC PASS run against currentmain, viagh api repos/diffplug/dormouse/compare/...). This is a genuine new production dependency on a disclosed root (dormouse-lib). Verified it is legitimately used (lib/src/host/agent-browser-host.ts,lib/src/host/browser-viewer.ts,lib/src/host/browser-host.ts— Node-side host modules bundled into both hosts) and is already correctly disclosed: the FAIL-IF-1 regeneration above produced no diff, confirmingdependencies-npm.jsonalready reflects it. No lockfile change was needed sincewswas already resolved elsewhere in the graph. This is exactly the class of change the CI regeneration gate (FAIL IF 2) exists to catch per the rationale'sws/honohistory, and it passed cleanly this time. INFO, not a finding.Non-registry lockfile resolutions: grepped
pnpm-lock.yamlfortarball:/http(s)://resolutions outside the npm registry. Found three kinds: (1)@diffplug/xterm-addon-webgl-sdf, a GitHub-release tarball, iscanopy's dependency only —canopyis inexcludedWorkspacePackages(Storybook-only lab,docs/specs/webgl-text.mddocuments the fork pipeline) and is not reachable from any product root (confirmed under check 3), so it correctly never reaches the disclosure or a user's machine. (2)pgstencil/@pgstencil/auth, resolved viafile:vendor/*.tgzperpnpm-workspace.yaml'soverrides, belong tohosted/dormouse-hosted, which is also excluded — pgstencil provenance is thehosteddomain's scope (docs/specs/security-hosted.md), not this one. (3)nodejs.org/unofficial-builds.nodejs.orgtarball URLs under the rootnode: runtime:24.18.0devEngines entry are pnpm's own runtime-provisioning URLs for the pinned Node version already covered by the Bundled Runtime checks above. None of the three represent an undisclosed package reaching a user's machine. INFO.Install scripts in production dependencies:
pnpm-workspace.yaml'sallowBuildsmap permits native builds forworkerd,@swc/core,esbuild,node-pty, andsharp, and blocks them forcpu-features,protobufjs,ssh2,@vscode/vsce-sign, andkeytar. Traced each allowed package withpnpm whyagainst the six product roots' directdependencies(notdevDependencies): onlynode-ptyis a direct runtime dependency of a shipped root (dormouse/ vscode-ext anddormouse-sidecar), which is expected (native PTY addon) and already disclosed.esbuild,@swc/core, andworkerdonly reachdormouse-hosted/ build tooling (wrangler, storybook, argos-ci), which is excluded from the shipped graph.sharpis pulled in as adependencies-declared transitive ofascii-splashunderdormouse-website(excluded — browser-only, andsharp's native binary cannot run in a browser regardless, so it is a build-time-only artifact) and otherwise only asdevDependenciesofdormouse-hosted/dormouse-libtooling. No allowed-build package reaches a shipped root through an undisclosed path. INFO.Any package reachable but undisclosed: none found. The root-completeness derivation (check 3) accounts for all 11 workspace packages, and the clean
generate-deps.jsdiff (check 1) confirms the generated disclosure matches what the roots currently resolve to.CI and secrets
VERDICT: PASS
FAIL IF results
pull_request_targetappears outsidetend-*.yaml(security-ci.md "GitHub Actions Policies"): PASS. Grep of.github/workflows/**showspull_request_targetonly as anon:trigger intend-review.yaml(agent-managed, exempt) and as a code comment inhosted-preview.yml:75("Never expose deployment credentials to fork code or pull_request_target"), which is not a trigger.id-token: write/attestations: writeor thesecurity-auditjob'sactions: write(security-ci.md "GitHub Actions Policies"): PASS.argos.yml,ci.yml,hosted-preview.yml,hosted-production.ymldeclare only workflow-levelcontents: read(jobchangesin hosted-preview.yml additionally scopespull-requests: read, a read permission).release.ymlis workflow-levelcontents: read; itsbuild-standalone/build-vscodejobs addid-token: write+attestations: write(the documented exception, gated on therelease-attestenvironment admitting only admin-gatedv*tags), itssecurity-auditjob adds onlyactions: write(the documented exception), andpublish-vscodehas no job-level permissions block, so it inherits workflow-levelcontents: read.uses:ref in a non-tend-*.yamlworkflow is not pinned by commit SHA: PASS. Scanned everyuses:line inargos.yml,ci.yml,hosted-preview.yml,hosted-production.yml,release.yml,security-audit.yaml,workflow-audit.yaml— every ref is a 40-hex-character commit SHA with a version comment.tend-*.yamlfiles use tag pins (max-sixty/tend/claude@0.3.2,actions/checkout@v7,astral-sh/setup-uv@v10.2.0), consistent with the documented exemption.GITHUB_TOKENpermissions exceedcontents: write,pull-requests: write,issues: write,id-token: write,actions: read, or any read scope: PASS. Checked everypermissions:block (workflow- and job-level) in alltend-*.yaml,workflow-audit.yaml, andsecurity-audit.yaml— every declared scope is within the allowed set (contents: write,pull-requests: write/read,issues: write,actions: read,id-token: write).default_workflow_permissionsis notreadorcan_approve_pull_request_reviewsis notfalse: PASS.GET repos/diffplug/dormouse/actions/permissions/workflowreturns{"default_workflow_permissions":"read","can_approve_pull_request_reviews":false}.GET repos/diffplug/dormouse/private-vulnerability-reportingreturns{"enabled":true}.GET .../rulesets/16757376("Merge access"):target: branch,conditions.ref_name.include: ["~DEFAULT_BRANCH"],rules: [update, deletion, creation],bypass_actors: [{actor_id:5, actor_type:RepositoryRole, bypass_mode:exempt}]— matches spec exactly (target, all three blocked operations, sole admin bypass actor).GET .../rulesets/16757382("Tag operations"):target: tag,conditions.ref_name.include: ["~ALL"],rules: [creation, update], same sole admin bypass actor — matches spec exactly.dormouse-botholdsmaintainoradmin: PASS.GET repos/diffplug/dormouse/collaborators/dormouse-bot/permissionreturnspermission: "write",role_name: "write"— neithermaintainnoradmin.hosted-previewadmits a ref not admin-gated byTag operations/Merge access: PASS for every non-hosted-previewenvironment. Enumerated all 7 environments (GET .../environments) and each one'sdeployment-branch-policies:hosted-productionadmits onlymain(branch, covered by "Merge access" which blocks all non-adminupdate/creation/deletionon~DEFAULT_BRANCH);hosted-release-tagadmits onlymain(same);release-attestadmits only tag patternv*(covered by "Tag operations",~ALLtags, admin-onlycreation/update);security-auditadmitsmainand tagv*(both covered);tendadmits onlymain(covered);vscode-extension-publishadmits only tagv*(covered).hosted-preview(the named exception) admitsmainandrefs/pull/*/merge— checked instead against "Hosted Deployments" below.hosted-preview: admitsmain+refs/pull/*/merge,required_reviewers= [nedtwigg, edgartwigg],prevent_self_review: false(self-review is explicitly allowed by spec),can_admins_bypass: false.hosted-production: admits onlymain, same two reviewers,can_admins_bypass: false.hosted-release-tag: admits onlymain, same two reviewers,can_admins_bypass: false.hosted-preview: PASS. Repo-level secrets are exactlyARGOS_TOKEN,CHROMATIC_PROJECT_TOKEN(0 Hosted-related names); org-level secrets: 0 entries.hosted-preview's environment secrets (CLOUDFLARE_API_TOKEN,NEON_API_KEY,PREVIEW_AUTH_SECRET) are distinct, environment-scoped GitHub secret objects fromhosted-production's ownCLOUDFLARE_API_TOKEN— GitHub environment secrets are never shared across environments by name, so no production secret value can be present inhosted-previewthrough GitHub's placement mechanism; this is the limit of what "inspect GitHub secret placement" can determine (the underlying token's actual Cloudflare/Neon privilege scope is not GitHub-readable).HOSTED_TAG_TOKENappears outsidehosted-release-tag, or that environment is used by a job other thantaginhosted-production.yml: PASS.HOSTED_TAG_TOKENdoes not appear in any repo secret, org secret, or any other environment's secret listing (in facthosted-release-tag's own secret listing is currently empty — 0 entries — a provisioning gap, not a placement violation).grepof.github/workflows/**showshosted-release-tagreferenced only once, as theenvironment:of thetagjob inhosted-production.yml, andHOSTED_TAG_TOKENreferenced only in that same job.main, or a Hosted production tag can run before live verification succeeds: PASS.hosted-preview.yml'sdeployjob requiresneeds: verifyand itsif:excludes forks (github.event.pull_request.head.repo.full_name == github.repository);cleanupchecks outrefs/heads/mainexplicitly, not the PR ref.hosted-production.yml'stagjob hasneeds: deploy, anddeployitself runs the live smoke check (production.mjs smoke) as its last step before finishing, sotagcannot start until that verification succeeds..config/tend.yamldoes not setmerge: restricted, or anytend-*.yamlpasses anothermerge:: PASS..config/tend.yamlsetsmerge: restricted; everytend-*.yamlthat embeds amerge:key (tend-ci-fix.yaml,tend-mention.yaml,tend-nightly.yaml,tend-notifications.yaml,tend-review-runs.yaml,tend-review.yaml,tend-triage.yaml,tend-weekly.yaml) passesmerge: restricted, none other.CHROMATIC_PROJECT_TOKENorARGOS_TOKENis missing fromsecrets.allowedin.config/tend.yaml: PASS..config/tend.yaml'ssecrets.allowedlists exactlyCHROMATIC_PROJECT_TOKENandARGOS_TOKEN.github-actionsmanager can update.github/workflows/tend-*.yaml: PASS..github/renovate.jsonpackageRuleshas a rule withmatchManagers: ["github-actions"],matchFileNames: [".github/workflows/tend-*.yaml"],enabled: false.tend-*.yamlpinsmax-sixty/tendbelow0.1.19: PASS. Everytend-*.yaml'smax-sixty/tend/claude@0.3.2(>= 0.1.19).tend-*.yamlworkflow uses an unpinned action reference: PASS. Alluses:refs intend-*.yamlare tag pins with an explicit version (actions/checkout@v7,astral-sh/setup-uv@v10.2.0,max-sixty/tend/claude@0.3.2) — none is@mainor bare/unversioned..github/workflows/workflow-audit.yamlstarts deriving its lower bound from anything the pusher controls: PASS.SINCEis read fromgh api .../actions/workflows/workflow-audit.yaml/runs?status=success&per_page=1 --jq '.workflow_runs[0].created_at'(server-set), falling back to25 hours agoonly when no prior successful run exists; no pusher-controlled timestamp (e.g. committer date,--since) is used..github/audit/or.vscode/is outside any consumer ofworkflow-audit.yaml's diff window: PASS.WINDOW=(.github/workflows/ .config/tend.yaml .github/audit/ .vscode/)is the single definition;WINDOW_NON_WORKFLOW=("${WINDOW[@]:1}")is derived from it (not hand-duplicated);COMMITS(git log … -- "${WINDOW[@]}"),own_changes(),is_clean_merge(),is_renovate_pin_bump()'s refusal, andis_tend_regen()'s refusal all referenceWINDOW/WINDOW_NON_WORKFLOWrather than a separately hand-maintained list..github/workflows/workflow-audit.yamlis missing, disabled, or has not produced a successful run in the last 48 hours: PASS.GET .../actions/workflows/workflow-audit.yamlshowsstate: active; the 5 most recent runs are allconclusion: success, most recently2026-09-24T12:41:20Z(within 48h of the audit's run time, 2026-09-25).vscode-extension-publishlacks nonempty required reviewers,prevent_self_review: true, orcan_admins_bypass: false: PASS. Environment API showsrequired_reviewers= [nedtwigg, edgartwigg] (nonempty),prevent_self_review: true,can_admins_bypass: false.release.ymlis missing thevscode-extension-publishenvironment on the VS Code publish job, orVSCE_PAT/OVSX_PATare referenced from a job not bound to that environment: PASS.publish-vscodejob declaresenvironment: {name: vscode-extension-publish}. Repo-wide grep showsVSCE_PAT/OVSX_PATreferenced only atrelease.yml:347and:359, both inside that same job.release.ymluses production desktop signing secrets in CI, or stops generating an ephemeral Tauri updater key for unsigned CI artifacts: PASS.build-standaloneruns "Generate ephemeral Tauri updater key" (tauri signer generate --ci --write-keys … --force) and exports it asTAURI_SIGNING_PRIVATE_KEY; repo-wide grep of.github/workflows/finds no reference toAPPLE_SIGN_PASS,EV_SIGN_PIN, or a non-ephemeralTAURI_SIGNING_PRIVATE_KEY.scripts/sign-and-deploy.shstops verifying GitHub artifact attestations, stops verifying SHA-256 manifests, or stops using PIV-backed Windows signing: PASS.verify_downloaded_artifact()callsgh attestation verifywith--cert-identity/--cert-oidc-issuer/--source-ref/--source-digest, andcheck_sha256_manifest()runssha256sum -c/shasum -a 256 -c;sign_windows()callsjsign --storetype PIV.TAURI_SIGNING_PRIVATE_KEYis passed on a command line, orEV_SIGN_PINis passed literally tojsign --storepass: PASS.TAURI_SIGNING_PRIVATE_KEYis exported as an env var beforetauri signer sign "$bundle"(never appears as a flag value);jsign --storepass env:EV_SIGN_PINpasses the literal stringenv:EV_SIGN_PIN(an indirection token jsign itself resolves from its environment), not the PIN value.APPLE_SIGN_PASSis passed asxcrun notarytool --password "$APPLE_SIGN_PASS"(argv) — this is the documented, accepted "Known gap" in security-ci.md, not a FAIL IF violation..github/workflows/security-audit.yamlis missing/disabled, or thegh workflow rundispatch /gh run watch --exit-status/publish-vscode'sneeds:edge is gone (security-audit.md release-gate check): PASS.GET .../actions/workflows/security-audit.yamlshowsstate: active.release.yml'ssecurity-auditjob runsgh workflow run "$workflow" … --ref "$tag"thengh run watch "$run_id" … --exit-status;publish-vscodedeclaresneeds: [build-standalone, build-vscode, security-audit].docs/specs/security*.mdspec is in no domain's scope, in two, or a scope names a nonexistent file (security-audit.md "Domains"): PASS. Manually cross-checked each domain file's**Scope**bullet list against the 7 non-rationaledocs/specs/security*.mdfiles:ci-and-secretsclaimssecurity.md,security-ci.md,security-audit.md;application-securityclaimssecurity-local.md,security-remote.md;hostedclaimssecurity-hosted.md;supply-chainclaimssecurity-supply-chain.md— exactly one claimant each, no orphan, no dangling path.node scripts/spec-lint.mjs(which mechanically enforces this as "check 16") independently confirms:spec-lint: OK (35 specs, 71 files checked).application-security/hostedsubagents, or either scope is merged into a context also carrying another domain: PASS..github/audit/orchestrator.md§1 spawns exactlysupply-chain,ci-and-secrets,application-security,hostedas four separatesubagent_typeTask calls in one message; each domain file (.github/audit/*.md) has its own single-domain**Scope**block, none combined.application-security/hosteddoes not run on a stronger model than the mechanical domains, in bothsecurity-audit.yaml'sclaude_argsandscripts/security-audit-local.sh: PASS.security-audit.yaml'sclaude_argssets--model sonnetas the session default and the--agentsJSON overrides"model":"opus"for exactlyapplication-securityandhosted.scripts/security-audit-local.sh'srun_domain()setsmodel_args="--model sonnet"by default and overrides to--model opusforapplication-security|hostedvia the same case statement..github/audit/is missing a prompt file the workflow names, orsecurity-audit-local.shstops running from those same files: PASS. All six files (_preamble.md,orchestrator.md,supply-chain.md,ci-and-secrets.md,application-security.md,hosted.md) exist;security-audit-local.shloops over exactly this set at startup (for f in _preamble orchestrator supply-chain ci-and-secrets application-security hosted) and errors out if any is missing, thenrun_domain()reads_preamble.md+$domain.mdviacat, matching the workflow's--agentsprompt pointers..config/tend.yamland workflow YAML blobs from the audited commit: PASS.is_tend_regen()inworkflow-audit.yaml(lines 268-273) walksgit ls-tree -r "$sha" -- .config/tend.yaml .github/workflows/and returns failure (1) unless every entry's mode is100644or100755(rejecting symlinks/submodules) and every path is exactly.config/tend.yamlor matches.github/workflows/[^/]+\.ya?ml$.untilloop over the fragments' sentinels, breaking on its own sub-cap, re-issued under a bounded 32-minute deadline persisted to a file: PASS..github/audit/orchestrator.md§2 definesDEADLINE_FILE="$RUNNER_TEMP/audit-deadline"seeded tonow + 1920(32 min) only if absent, anuntil … finished …loop over all four fragment sentinels withCALL_ENDbreaking at 540s so the call always prints an answer, and explicit instructions to re-issue the block verbatim (reading back the sameDEADLINE_FILE) onSTILL WAITING.security-audit.yaml'sBASH_DEFAULT_TIMEOUT_MS: "600000"sets the cap this loop assumes, andtimeout-minutes: 40on the job exceeds the 32-minute wait deadline plus setup overhead.audit-report.md: PASS..github/audit/orchestrator.md§4 states verbatim: "Never end your turn whileaudit-report.mddoes not exist... If you have nothing left to wait on, merge §3 with whatever fragments exist and let its markers say the rest.".github/audit/_preamble.mdrequires fragments to be opened before the first check and appended to "as you determine them — never buffered... for one write-up at the end", and requires any delegating domain to "block for your delegates — never end your turn to wait", explicitly forbiddingrun_in_background. Both the orchestrator's wait loop (finished()) and merge step (emit()) test for the literal<!-- END OF REPORT -->sentinel via[ -s "$1" ] && [ "$(... | tail -n1)" = "<!-- END OF REPORT -->" ], not mere file existence.PASSwhile a subagent left no report fragment, norFAILunless some domain actually returned one: PASS..github/audit/orchestrator.md§4: "write no status file at all" whenever any domain is missing/empty/unreadable/unsentineled, and "PASS requires all four domains to pass";FAILrequires "any subagent returned FAIL" — a real domain verdict.security-audit.yaml's reporting step independently re-derives this from the fragments themselves (MISSING_FRAGMENTS,UNFINISHED,UNREADABLE_VERDICTS,INCONCLUSIVE_DOMAINSloops, none gated on$STATUS) rather than trusting the orchestrator's ownaudit-status.txt, so a prompt failure alone cannot produce a falsePASS.Redact secrets from agent outputstep is removed, stops covering any sink that is later published, or stops failing closed: PASS. The step isif: always(), runs before the artifact-upload and reporting steps, redactsAUDIT_PATandCLAUDE_CODE_OAUTH_TOKENfrom$TRANSCRIPT,audit-report.md, and every file in$AUDIT_FRAGMENTS(all four domain fragments — the identical set named in the job-levelenv:and consumed by the reporting step's guard loops and the artifact upload'spath:), and on any Node error runsrm -f "$TRANSCRIPT" audit-report.md $AUDIT_FRAGMENTS; exit 1— deleting rather than shipping an unredacted sink.NOTESblock in the "Surface result" step is five independentif [ -n "${VAR:-}" ]blocks (DISSENTING,MISSING_FRAGMENTS,UNREADABLE_VERDICTS,UNFINISHED,INCONCLUSIVE_DOMAINS) plus one forFILE_STATUS = MISSING, each appending its own line independently — no combinatorial branching.for f in $AUDIT_FRAGMENTSloops (the missing-fragment check and the sentinel/verdict-line check) run unconditionally, before theSTATUSescalation block; the code comments explicitly note "Both loops now run UNCONDITIONALLY."VERDICT: PASSas passing, fails to recognize aVERDICT: FAILprefix as dissent, ignores an inconclusive domain, accepts a fragment with no completion sentinel as finished, or accepts status text other than literalPASS/FAIL: PASS. The verdictcasematches'VERDICT: FAIL'*(prefix, so "FAIL" plus explanation still dissents) intoDISSENTING, only the exact string'VERDICT: PASS'as passing,'VERDICT: INCONCLUSIVE'intoINCONCLUSIVE_DOMAINS, and everything else intoUNREADABLE_VERDICTS; the sentinel test (tail -n1after stripping blank lines) is a separate, unconditional check that flagsUNFINISHEDregardless of the verdict line.FILE_STATUSis parsed withcase "${FILE_STATUS:-}" in PASS|FAIL) ;; *) FILE_STATUS=MISSING ;; esac— only the literal strings pass through.AUDIT_PATis provisioned before the audit runs is removed or bypassed: PASS.security-audit.yaml's "Verify AUDIT_PAT is provisioned" step runs after checkout/setup-node/install and before the "Audit against the security specs" step, checks[ -n "$AUDIT_PAT" ], and on failure writesaudit-report.md/audit-status.txtandexit 1(job fails, no audit step runs).Qualitative findings
Truncated to fit: the full body is 336081 characters. The untruncated
audit-report.mdis in this run'saudit-transcriptartifact (download).