# Security Finalizer Implementation Plan > **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. **Goal:** Finalize a captured immutable candidate into one private random exact-five staging directory with strict v3 verification records and deterministic cleanup. **Architecture:** `finalizeVerifiedPromotion` captures the archive, provider reports, and public keys before validation, evaluates only those captured bytes against archived local evidence, generates both v3 records in memory, and publishes five read-only files under a descriptor-relative runner-temp directory. The generated workflow consumes the returned staging path immediately and always invokes the token-bound cleanup CLI. **Tech Stack:** Node.js 24, TypeScript, Zod, Vitest, bubblewrap-independent filesystem primitives, generated Gitea Actions YAML. ## Global Constraints - Never accept pre-existing provider- or promotion-verification JSON as an input. - Stage exactly archive, vulnerability report, provenance attestation, provider verification v3, and promotion verification v3. - Use injected time and randomness for deterministic tests. - Use a random runner-temp directory at mode `0700`, files at `0400`, and `O_EXCL | O_NOFOLLOW` creation. - Do not claim that TypeScript closes the Gitea upload action pathname-reopen issue or guarantees `renameat2` semantics. --- ### Task 1: Exact-five finalizer contract **Files:** - Modify: `tests/unit/ci-artifact-contract.test.ts` - Modify: `scripts/lib/promotion-stager.ts` - Modify: `scripts/contracts/promotion-artifacts.ts` **Interfaces:** - Consumes: `finalizeVerifiedPromotion(input, dependencies)` with captured archive/report/key inputs. - Produces: `{ stagingRoot, cleanupToken, files }` where `files` is the canonical exact-five name/digest list. - [ ] **Step 1: Write failing tests** for no pre-existing records, strict distinct v3 roles, exact provider-record and local-assessment hashes, full run/source/candidate/nonces/key/trust bindings, key rotation, captured-source mutation, and no output on failures. - [ ] **Step 2: Run RED:** `corepack pnpm exec vitest run tests/unit/ci-artifact-contract.test.ts -t "verified promotion finalizer" --maxWorkers=1` and retain the first contract failure. - [ ] **Step 3: Implement minimal finalizer changes** so all validation and record generation consume captured bytes and both PASS records are created only after local/provider PASS. - [ ] **Step 4: Run GREEN:** rerun the focused Vitest command and require zero failures. ### Task 2: Private staging and cleanup **Files:** - Modify: `tests/unit/ci-artifact-contract.test.ts` - Modify: `scripts/lib/promotion-stager.ts` - Modify: `scripts/cleanup-verified-promotion.ts` **Interfaces:** - Consumes: injected `randomBytes`, runner-temp root, cleanup token. - Produces: descriptor-relative random staging at `0700`, exact files at `0400`, and token-bound cleanup. - [ ] **Step 1: Write failing tests** for deterministic naming, modes, stable-path absence, exclusive no-follow creation, parent/leaf substitution, success cleanup, and failure cleanup. - [ ] **Step 2: Run RED:** use the Task 1 focused Vitest command and retain the first filesystem-boundary failure. - [ ] **Step 3: Implement minimal private publication and cleanup changes** using `/proc/self/fd` where available, bounded writes, identity rechecks, and removal of owned partial roots. - [ ] **Step 4: Run GREEN:** rerun the focused Vitest command and require zero failures. ### Task 3: Workflow handoff **Files:** - Modify: `config/ci/gates.json` - Modify: `scripts/contracts/ci-gates.ts` - Modify: `scripts/stage-verified-promotion.ts` - Modify: `.gitea/workflows/quality-gates.yml` - Modify: `tests/unit/ci-workflow-generation.test.ts` **Interfaces:** - Consumes: finalizer step outputs `staging_root` and `cleanup_token`. - Produces: setup, three downloads, finalizer, immediate non-`always()` exact-five upload, and `always()` cleanup ordering. - [ ] **Step 1: Write/update failing workflow assertions** that reject standalone extraction, stable staging paths, missing `--ignore-scripts`, upload indirection, or cleanup ordering drift. - [ ] **Step 2: Run RED:** `node scripts/generate-ci-workflow.ts --check` and the workflow snapshot test. - [ ] **Step 3: Update the CI contract/config and regenerate YAML** with the finalizer output path and cleanup environment. - [ ] **Step 4: Run GREEN:** require workflow byte check and snapshot test PASS. ### Task 4: Full verification and durable report **Files:** - Modify: `.superpowers/sdd/2026-08-01-quality-architecture-remediation/task-3-report.md` **Interfaces:** - Consumes: focused finalizer, provider, workflow, type, and lint evidence. - Produces: durable RED/GREEN evidence and a commit-ready report without overclaiming platform handoff guarantees. - [ ] **Step 1: Run verification:** focused finalizer/provider tests, `check:supply-chain:provider-fixtures`, workflow `--check`, `check:types`, and `lint`. - [ ] **Step 2: Append exact RED/GREEN commands and outcomes** to the task report, including the remaining Gitea upload and `renameat2` limitations. - [ ] **Step 3: Inspect diff/status** and report completion before committing.