Files
tech-log-frontend/docs/superpowers/plans/2026-08-02-security-finalizer.md

83 lines
5.2 KiB
Markdown

# 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.