[E00-S01-T01] Create workspace/package manifests #154

Closed
opened 2026-08-27 00:06:28 +00:00 by kpcto · 11 comments
Owner

Parent story: [E00-S01] Workspace bootstrap (#58)

Intent

Create the pnpm workspace and package manifests so apps, core packages and extensions have a predictable dependency graph from day one.

Acceptance criteria

  • pnpm 11.23.0 workspace committed with a frozen lockfile
  • apps, packages and extensions separated into distinct workspace entries
  • a clean clone installs with pnpm install --frozen-lockfile

Explicitly out of scope

  • The strict base tsconfig (that is E00-S01-T02)
  • ESM package boundaries (that is E00-S01-T03)
  • The dependency-boundary rule and architecture test (that is E00-S01-T04)

Test plan

  • run a clean pnpm install --frozen-lockfile on a fresh clone and confirm it succeeds
  • confirm the workspace lists apps/, packages/ and extensions/ as separate entries

Rollback note

  • Single commit; revert to remove. No database or migration changes.

Owning stream

platform

Risk quadrant

agent-full

> Parent story: [E00-S01] Workspace bootstrap (#58) ## Intent Create the pnpm workspace and package manifests so apps, core packages and extensions have a predictable dependency graph from day one. ## Acceptance criteria - pnpm 11.23.0 workspace committed with a frozen lockfile - apps, packages and extensions separated into distinct workspace entries - a clean clone installs with `pnpm install --frozen-lockfile` ## Explicitly out of scope - The strict base tsconfig (that is E00-S01-T02) - ESM package boundaries (that is E00-S01-T03) - The dependency-boundary rule and architecture test (that is E00-S01-T04) ## Test plan - run a clean `pnpm install --frozen-lockfile` on a fresh clone and confirm it succeeds - confirm the workspace lists apps/, packages/ and extensions/ as separate entries ## Rollback note - Single commit; revert to remove. No database or migration changes. ### Owning stream platform ### Risk quadrant agent-full
kpcto added this to the Sprint 0 milestone 2026-08-27 00:06:28 +00:00
kpcto added the
kind
task
status
ready
labels 2026-08-27 00:06:28 +00:00
bot-dispatcher added
status
proposed
and removed
status
ready
kind
task
labels 2026-08-27 00:06:30 +00:00
Member

Auto-reverted by dispatcher: DoR lint: required section "Intent" is empty; required section "Acceptance criteria" is empty; required section "Explicitly out of scope" is empty; required section "Test plan" is empty; required section "Rollback note" is empty; acceptance criteria: no bullet assertions found

status/ready may only be applied by a human maintainer.

> Auto-reverted by dispatcher: DoR lint: required section "Intent" is empty; required section "Acceptance criteria" is empty; required section "Explicitly out of scope" is empty; required section "Test plan" is empty; required section "Rollback note" is empty; acceptance criteria: no bullet assertions found `status/ready` may only be applied by a human maintainer.
kpcto added the
kind
task
label 2026-08-27 21:14:48 +00:00
kpcto added
status
ready
and removed
status
proposed
labels 2026-08-27 22:59:30 +00:00
bot-dispatcher added
loop
1
status
in-progress
and removed
status
ready
labels 2026-08-27 22:59:31 +00:00
Member
agent: dispatcher
phase: complete
plan_summary: Dispatch #154: [E00-S01-T01] Create workspace/package manifests (platform, security-gated)
```yaml agent: dispatcher phase: complete plan_summary: Dispatch #154: [E00-S01-T01] Create workspace/package manifests (platform, security-gated) ```
bot-dispatcher added the needs/security-reviewneeds/security-review labels 2026-08-27 22:59:32 +00:00
Member
agent: implementer
phase: start
issue: 154
plan_summary: >
  Implement #154 [E00-S01-T01] Create workspace/package manifests on feature/154:
  (1) root package.json pinning packageManager pnpm@11.23.0, (2) pnpm-workspace.yaml
  with distinct entries apps/*, packages/*, extensions/*, (3) minimal skeleton
  package manifests in each workspace group so the groups are real pnpm workspace
  entries, (4) committed pnpm-lock.yaml (frozen lockfile) generated by pnpm 11.23.0,
  (5) minimal CI workflow that runs pnpm install --frozen-lockfile, (6) verify a
  clean clone installs with --frozen-lockfile. Out of scope per brief: tsconfig.base
  (T02), ESM boundaries (T03), dependency-boundary rule/test (T04). Then open PR to
  main with a criterion->test table and confirm CI green.
```yaml agent: implementer phase: start issue: 154 plan_summary: > Implement #154 [E00-S01-T01] Create workspace/package manifests on feature/154: (1) root package.json pinning packageManager pnpm@11.23.0, (2) pnpm-workspace.yaml with distinct entries apps/*, packages/*, extensions/*, (3) minimal skeleton package manifests in each workspace group so the groups are real pnpm workspace entries, (4) committed pnpm-lock.yaml (frozen lockfile) generated by pnpm 11.23.0, (5) minimal CI workflow that runs pnpm install --frozen-lockfile, (6) verify a clean clone installs with --frozen-lockfile. Out of scope per brief: tsconfig.base (T02), ESM boundaries (T03), dependency-boundary rule/test (T04). Then open PR to main with a criterion->test table and confirm CI green. ```
Member
agent: security
issue: 154
pr: 368
head_branch: feature/154
phase: started
verdict: pending
scope:
  - secrets scan (gitleaks)
  - dependency scan (osv-scanner)
  - authz trace on new routes/handlers
  - input boundaries / injection / SSRF / deserialization
  - pipeline tripwire (agents/, CI config, .gitea/workflows/)
note: >
  Security review starting now. This is the interim notice; the final
  structured verdict (approve | request-changes) follows in a second
  comment when the audit completes.
```yaml agent: security issue: 154 pr: 368 head_branch: feature/154 phase: started verdict: pending scope: - secrets scan (gitleaks) - dependency scan (osv-scanner) - authz trace on new routes/handlers - input boundaries / injection / SSRF / deserialization - pipeline tripwire (agents/, CI config, .gitea/workflows/) note: > Security review starting now. This is the interim notice; the final structured verdict (approve | request-changes) follows in a second comment when the audit completes. ```
Member
agent: implementer
phase: complete
issue: 154
pr: "http://gitea:3000/Fabrika/PersonalBlog/pulls/368"
head_branch: feature/154
head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77
status: ready-for-review
summary: >
  Done #154 [E00-S01-T01]. PR #368 open on feature/154: root package.json pins
  packageManager pnpm@11.23.0; pnpm-workspace.yaml lists distinct entries apps/*,
  packages/*, extensions/*; skeleton manifests in each group (apps/server,
  packages/core, extensions/example); committed frozen lockfile (lockfileVersion
  9.0) generated by pnpm 11.23.0; .gitignore; minimal CI running the frozen
  install. Out of scope respected: no tsconfig (T02), no ESM boundaries (T03),
  no dependency-boundary rule/test (T04).
criterion_to_test:
  - criterion: "pnpm 11.23.0 workspace committed with a frozen lockfile"
    result: pass
    evidence: >
      packageManager: pnpm@11.23.0 in root package.json; pnpm-lock.yaml committed
      (lockfileVersion 9.0). CI run 33 step 'Install dependencies (frozen
      lockfile)' succeeds: "Scope: all 4 workspace projects ... Done in 3.5s using
      pnpm v11.23.0".
  - criterion: "apps, packages and extensions separated into distinct workspace entries"
    result: pass
    evidence: >
      pnpm-workspace.yaml has three separate glob entries; skeleton package.json in
      each group; CI step 'Verify workspace groups' prints all 4 projects:
      personal-blog (root), @personal-blog/server (apps/server),
      @personal-blog/example-extension (extensions/example), @personal-blog/core
      (packages/core).
  - criterion: "a clean clone installs with pnpm install --frozen-lockfile"
    result: pass
    evidence: >
      Fresh git clone -> pnpm install --frozen-lockfile (fresh store) exits 0,
      "Already up to date", lockfile unchanged (git status clean after install);
      CI re-runs the same command on a clean checkout and passes.
ci:
  - name: "CI / Frozen lockfile install (pull_request)"
    status: success
    url: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/33"
notes: >
  Minimal CI workflow added so the acceptance test runs on every PR; the full CI
  quality pipeline (typecheck/lint/tests/architecture) is E00-S05, out of scope.
```yaml agent: implementer phase: complete issue: 154 pr: "http://gitea:3000/Fabrika/PersonalBlog/pulls/368" head_branch: feature/154 head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77 status: ready-for-review summary: > Done #154 [E00-S01-T01]. PR #368 open on feature/154: root package.json pins packageManager pnpm@11.23.0; pnpm-workspace.yaml lists distinct entries apps/*, packages/*, extensions/*; skeleton manifests in each group (apps/server, packages/core, extensions/example); committed frozen lockfile (lockfileVersion 9.0) generated by pnpm 11.23.0; .gitignore; minimal CI running the frozen install. Out of scope respected: no tsconfig (T02), no ESM boundaries (T03), no dependency-boundary rule/test (T04). criterion_to_test: - criterion: "pnpm 11.23.0 workspace committed with a frozen lockfile" result: pass evidence: > packageManager: pnpm@11.23.0 in root package.json; pnpm-lock.yaml committed (lockfileVersion 9.0). CI run 33 step 'Install dependencies (frozen lockfile)' succeeds: "Scope: all 4 workspace projects ... Done in 3.5s using pnpm v11.23.0". - criterion: "apps, packages and extensions separated into distinct workspace entries" result: pass evidence: > pnpm-workspace.yaml has three separate glob entries; skeleton package.json in each group; CI step 'Verify workspace groups' prints all 4 projects: personal-blog (root), @personal-blog/server (apps/server), @personal-blog/example-extension (extensions/example), @personal-blog/core (packages/core). - criterion: "a clean clone installs with pnpm install --frozen-lockfile" result: pass evidence: > Fresh git clone -> pnpm install --frozen-lockfile (fresh store) exits 0, "Already up to date", lockfile unchanged (git status clean after install); CI re-runs the same command on a clean checkout and passes. ci: - name: "CI / Frozen lockfile install (pull_request)" status: success url: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/33" notes: > Minimal CI workflow added so the acceptance test runs on every PR; the full CI quality pipeline (typecheck/lint/tests/architecture) is E00-S05, out of scope. ```
Member
agent: tester
issue: 154
pr: 368
head_branch: feature/154
head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77
phase: start
objective: >-
  Independently probe PR #368 for #154 against the acceptance criteria
  (no edits to the implementer's tests or any PR files).
acceptance:
  - pnpm 11.23.0 workspace committed with a frozen lockfile
  - apps, packages and extensions separated into distinct workspace entries
  - a clean clone installs with `pnpm install --frozen-lockfile`
constraints:
  - never edit the implementer's tests in the same PR
plan: >-
  Fresh clone of feature/154 into a clean directory, inspect the workspace
  manifests (package.json, pnpm-workspace.yaml, pnpm-lock.yaml), then run
  `pnpm install --frozen-lockfile` against a fresh pnpm store using the
  pinned pnpm 11.23.0, and confirm the workspace groups are distinct.
note: >-
  Interim notice. The structured verdict with evidence and CI links follows
  in a second comment when the probe completes.
```yaml agent: tester issue: 154 pr: 368 head_branch: feature/154 head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77 phase: start objective: >- Independently probe PR #368 for #154 against the acceptance criteria (no edits to the implementer's tests or any PR files). acceptance: - pnpm 11.23.0 workspace committed with a frozen lockfile - apps, packages and extensions separated into distinct workspace entries - a clean clone installs with `pnpm install --frozen-lockfile` constraints: - never edit the implementer's tests in the same PR plan: >- Fresh clone of feature/154 into a clean directory, inspect the workspace manifests (package.json, pnpm-workspace.yaml, pnpm-lock.yaml), then run `pnpm install --frozen-lockfile` against a fresh pnpm store using the pinned pnpm 11.23.0, and confirm the workspace groups are distinct. note: >- Interim notice. The structured verdict with evidence and CI links follows in a second comment when the probe completes. ```
Member
agent: tester
issue: 154
pr: 368
head_branch: feature/154
head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77
phase: complete
verdict: pass
summary: >-
  Independent probe of PR #368 passed all three acceptance criteria. No PR or
  implementer-test file was edited; the only mutation was a scratch copy under
  /tmp used for a negative control on frozen-lockfile enforcement.
criterion_to_test:
  - criterion: "pnpm 11.23.0 workspace committed with a frozen lockfile"
    result: pass
    evidence: >-
      Root package.json pins packageManager: pnpm@11.23.0. pnpm-lock.yaml is
      committed (lockfileVersion 9.0, importers for root + apps/server +
      packages/core + extensions/example). Fresh-store install reports "Done
      in 2.3s using pnpm v11.23.0" and git status is clean afterward.
      Negative control: injecting an un-locked dependency then running
      `pnpm install --frozen-lockfile` fails with ERR_PNPM_OUTDATED_LOCKFILE,
      proving the flag is genuinely enforced rather than silently regenerating.
  - criterion: "apps, packages and extensions separated into distinct workspace entries"
    result: pass
    evidence: >-
      pnpm-workspace.yaml contains three distinct, non-overlapping entries:
      apps/*, packages/*, extensions/*. `pnpm -r list --depth -1` resolves 4
      projects: personal-blog (root), @personal-blog/server (apps/server),
      @personal-blog/core (packages/core), @personal-blog/example-extension
      (extensions/example).
  - criterion: "a clean clone installs with pnpm install --frozen-lockfile"
    result: pass
    evidence: >-
      Fresh `git clone --branch feature/154` at a2fa1de with a fresh pnpm
      store, then `pnpm install --frozen-lockfile` exits 0 ("Already up to
      date", "Scope: all 4 workspace projects"). Working tree remains clean.
ci:
  - name: "CI / Frozen lockfile install (pull_request)"
    status: success
    run: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/33"
    job: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/33/jobs/45"
    evidence: >-
      Job 'Frozen lockfile install' — 5/5 steps success. Log confirms Node
      v24.20.0, corepack downloading pnpm-11.23.0.tgz, "Scope: all 4 workspace
      projects", "Done in 3.5s using pnpm v11.23.0", the 4-project workspace
      listing, and "Job succeeded".
notes: >-
  No deviations from acceptance criteria found. Out-of-scope items (tsconfig,
  ESM boundaries, dependency-boundary rule) are correctly absent. Constraint
  honored: no implementer test or PR file was edited.
```yaml agent: tester issue: 154 pr: 368 head_branch: feature/154 head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77 phase: complete verdict: pass summary: >- Independent probe of PR #368 passed all three acceptance criteria. No PR or implementer-test file was edited; the only mutation was a scratch copy under /tmp used for a negative control on frozen-lockfile enforcement. criterion_to_test: - criterion: "pnpm 11.23.0 workspace committed with a frozen lockfile" result: pass evidence: >- Root package.json pins packageManager: pnpm@11.23.0. pnpm-lock.yaml is committed (lockfileVersion 9.0, importers for root + apps/server + packages/core + extensions/example). Fresh-store install reports "Done in 2.3s using pnpm v11.23.0" and git status is clean afterward. Negative control: injecting an un-locked dependency then running `pnpm install --frozen-lockfile` fails with ERR_PNPM_OUTDATED_LOCKFILE, proving the flag is genuinely enforced rather than silently regenerating. - criterion: "apps, packages and extensions separated into distinct workspace entries" result: pass evidence: >- pnpm-workspace.yaml contains three distinct, non-overlapping entries: apps/*, packages/*, extensions/*. `pnpm -r list --depth -1` resolves 4 projects: personal-blog (root), @personal-blog/server (apps/server), @personal-blog/core (packages/core), @personal-blog/example-extension (extensions/example). - criterion: "a clean clone installs with pnpm install --frozen-lockfile" result: pass evidence: >- Fresh `git clone --branch feature/154` at a2fa1de with a fresh pnpm store, then `pnpm install --frozen-lockfile` exits 0 ("Already up to date", "Scope: all 4 workspace projects"). Working tree remains clean. ci: - name: "CI / Frozen lockfile install (pull_request)" status: success run: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/33" job: "http://gitea:3000/Fabrika/PersonalBlog/actions/runs/33/jobs/45" evidence: >- Job 'Frozen lockfile install' — 5/5 steps success. Log confirms Node v24.20.0, corepack downloading pnpm-11.23.0.tgz, "Scope: all 4 workspace projects", "Done in 3.5s using pnpm v11.23.0", the 4-project workspace listing, and "Job succeeded". notes: >- No deviations from acceptance criteria found. Out-of-scope items (tsconfig, ESM boundaries, dependency-boundary rule) are correctly absent. Constraint honored: no implementer test or PR file was edited. ```
Member
agent: security
issue: 154
pr: 368
head_branch: feature/154
head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77
phase: complete
verdict: approve
diff_summary: >-
  8 files added, 84 insertions, 0 deletions. Base main (7c21255) is an empty
  tree, so this is a pure net-new bootstrap; no existing file is modified.
checks:
  secrets:
    tool: gitleaks
    commands:
      - gitleaks detect --source . --no-git --redact
      - gitleaks detect --source . --redact
    result: clean
    evidence: >-
      Both runs exit 0 with "no leaks found" (working tree at a2fa1de, ~1.72 KB;
      full history, 32 commits, ~107 KB). No secrets in code, manifests,
      lockfile or commit history.
  dependencies:
    tool: osv-scanner
    command: osv-scanner --recursive .
    result: nothing-to-scan
    evidence: >-
      Exit 128 "No package sources found": pnpm-lock.yaml declares 0 packages
      (all importers are empty {}). Manually verified the lockfile has no
      dependencies, no git/url tarball deps, no overrides and no
      patchedDependencies anywhere in the diff. Zero third-party dependency
      surface in this PR.
  sast:
    tool: semgrep
    result: skipped
    evidence: >-
      Binary not present in the security worker image (command -v semgrep
      fails); per playbook it is not installed ad hoc. Gap covered by the
      manual authz/input trace below.
  authz_trace:
    result: not-applicable
    evidence: >-
      No routes, handlers, endpoints or data access in the diff - only package
      manifests, .gitignore, a lockfile and one CI workflow. No default-allow
      path exists because no authorizable path exists.
  input_boundaries:
    result: not-applicable
    evidence: >-
      No code files, no parsing/validation/deserialization of untrusted data,
      no outbound requests with user-influenced URLs (no SSRF surface), and no
      template interpolation in any CI run step (all run: blocks are static
      strings, so no script-injection vector).
  pipeline_tripwire:
    diff_touches:
      - ".gitea/workflows/ci.yml"
    result: no-blocker
    assessment: >-
      Assessed explicitly per the review checklist. Base main (7c21255) is an
      empty tree: there is no pre-existing CI config, agents/ directory or
      review-process configuration to alter - the workflow is net-new and
      additive, not a modification of existing pipeline machinery. Audited
      line-by-line: no secrets.* usage, no pull_request_target (triggers are
      pull_request plus push to main only), no cache/artifact/service/container
      vectors, and the lockfile it installs is dependency-free, so
      pnpm install --frozen-lockfile executes no third-party lifecycle scripts.
      The workflow only adds a frozen-install verification gate (CI run 33 on
      a2fa1de: success) - it strengthens gating rather than weakening it.
      Scope/placement of CI in this task is kept as finding 2 below,
      non-blocking, for the stream owner.
findings:
  - id: 1
    severity: should
    file: ".gitea/workflows/ci.yml:13,15"
    what: >-
      Third-party CI actions (actions/checkout@v4, actions/setup-node@v4) are
      pinned to mutable major tags rather than immutable commit SHAs; runners
      resolve the tag at run time.
    exploit_path: >-
      A compromised or force-pushed upstream tag changes the code CI executes
      on every future PR/push of this repo.
    fix: >-
      Pin to full commit SHAs with a version comment, e.g.
      "uses: actions/checkout@<full-sha> # v4.x.y".
  - id: 2
    severity: should
    file: ".gitea/workflows/ci.yml"
    what: >-
      CI is outside issue #154's stated acceptance criteria (workspace +
      manifests + clean install); the full pipeline is owned by E00-S05. The
      implementer disclosed the file and uses it as frozen-install evidence,
      so this is a placement/sign-off note, not tampering.
    fix: >-
      Stream owner confirms the CI bootstrap lands here versus E00-S05;
      otherwise no change required.
  - id: 3
    severity: nit
    file: ".gitea/workflows/ci.yml:19"
    what: >-
      corepack enable downloads pnpm@11.23.0 from the registry at CI run time.
      The version pin via packageManager is exact (good - no range), but the
      fetch itself is not bound to a pinned integrity key set.
    fix: >-
      Optional hardening: vendor COREPACK_INTEGRITY_KEYS or use the pnpm
      standalone installer from a pinned URL. Acceptable as-is for sprint 0.
  - id: 4
    severity: nit
    file: ".gitignore:11"
    what: >-
      ".env.*" also matches ".env.example", which E00-S04 plans to commit; it
      would be silently ignored. Fails safe today (over-ignoring, not
      under-ignoring), but will surprise the next story.
    fix: >-
      Add a negation line "!.env.example" when that file lands in E00-S04.
  - id: 5
    severity: nit
    file: ".gitea/workflows/ci.yml:8"
    what: >-
      No least-privilege "permissions: contents: read" block. Gitea Actions
      support for it is limited; the value is documenting intent and
      forward-compatibility with GitHub-compatible runners.
    fix: >-
      Add permissions with contents read at workflow level.
verdict_rationale: >-
  Approve. Every security gate is clean or not-applicable with evidence above:
  no secrets in tree or history, zero third-party dependencies, no routes to
  authorize, no input/SSRF/deserialization surface, and no pipeline tampering.
  Remaining findings are two non-blocking "should" notes (action SHA pinning;
  CI scope sign-off) and three nits - none alters the verdict. The only
  pipeline-adjacent change is a net-new additive CI file on an empty base,
  audited line-by-line, which adds a frozen-lockfile gate rather than
  weakening anything.
```yaml agent: security issue: 154 pr: 368 head_branch: feature/154 head_sha: a2fa1dee32e728348db53eaaaae1d74e54ff5c77 phase: complete verdict: approve diff_summary: >- 8 files added, 84 insertions, 0 deletions. Base main (7c21255) is an empty tree, so this is a pure net-new bootstrap; no existing file is modified. checks: secrets: tool: gitleaks commands: - gitleaks detect --source . --no-git --redact - gitleaks detect --source . --redact result: clean evidence: >- Both runs exit 0 with "no leaks found" (working tree at a2fa1de, ~1.72 KB; full history, 32 commits, ~107 KB). No secrets in code, manifests, lockfile or commit history. dependencies: tool: osv-scanner command: osv-scanner --recursive . result: nothing-to-scan evidence: >- Exit 128 "No package sources found": pnpm-lock.yaml declares 0 packages (all importers are empty {}). Manually verified the lockfile has no dependencies, no git/url tarball deps, no overrides and no patchedDependencies anywhere in the diff. Zero third-party dependency surface in this PR. sast: tool: semgrep result: skipped evidence: >- Binary not present in the security worker image (command -v semgrep fails); per playbook it is not installed ad hoc. Gap covered by the manual authz/input trace below. authz_trace: result: not-applicable evidence: >- No routes, handlers, endpoints or data access in the diff - only package manifests, .gitignore, a lockfile and one CI workflow. No default-allow path exists because no authorizable path exists. input_boundaries: result: not-applicable evidence: >- No code files, no parsing/validation/deserialization of untrusted data, no outbound requests with user-influenced URLs (no SSRF surface), and no template interpolation in any CI run step (all run: blocks are static strings, so no script-injection vector). pipeline_tripwire: diff_touches: - ".gitea/workflows/ci.yml" result: no-blocker assessment: >- Assessed explicitly per the review checklist. Base main (7c21255) is an empty tree: there is no pre-existing CI config, agents/ directory or review-process configuration to alter - the workflow is net-new and additive, not a modification of existing pipeline machinery. Audited line-by-line: no secrets.* usage, no pull_request_target (triggers are pull_request plus push to main only), no cache/artifact/service/container vectors, and the lockfile it installs is dependency-free, so pnpm install --frozen-lockfile executes no third-party lifecycle scripts. The workflow only adds a frozen-install verification gate (CI run 33 on a2fa1de: success) - it strengthens gating rather than weakening it. Scope/placement of CI in this task is kept as finding 2 below, non-blocking, for the stream owner. findings: - id: 1 severity: should file: ".gitea/workflows/ci.yml:13,15" what: >- Third-party CI actions (actions/checkout@v4, actions/setup-node@v4) are pinned to mutable major tags rather than immutable commit SHAs; runners resolve the tag at run time. exploit_path: >- A compromised or force-pushed upstream tag changes the code CI executes on every future PR/push of this repo. fix: >- Pin to full commit SHAs with a version comment, e.g. "uses: actions/checkout@<full-sha> # v4.x.y". - id: 2 severity: should file: ".gitea/workflows/ci.yml" what: >- CI is outside issue #154's stated acceptance criteria (workspace + manifests + clean install); the full pipeline is owned by E00-S05. The implementer disclosed the file and uses it as frozen-install evidence, so this is a placement/sign-off note, not tampering. fix: >- Stream owner confirms the CI bootstrap lands here versus E00-S05; otherwise no change required. - id: 3 severity: nit file: ".gitea/workflows/ci.yml:19" what: >- corepack enable downloads pnpm@11.23.0 from the registry at CI run time. The version pin via packageManager is exact (good - no range), but the fetch itself is not bound to a pinned integrity key set. fix: >- Optional hardening: vendor COREPACK_INTEGRITY_KEYS or use the pnpm standalone installer from a pinned URL. Acceptable as-is for sprint 0. - id: 4 severity: nit file: ".gitignore:11" what: >- ".env.*" also matches ".env.example", which E00-S04 plans to commit; it would be silently ignored. Fails safe today (over-ignoring, not under-ignoring), but will surprise the next story. fix: >- Add a negation line "!.env.example" when that file lands in E00-S04. - id: 5 severity: nit file: ".gitea/workflows/ci.yml:8" what: >- No least-privilege "permissions: contents: read" block. Gitea Actions support for it is limited; the value is documenting intent and forward-compatibility with GitHub-compatible runners. fix: >- Add permissions with contents read at workflow level. verdict_rationale: >- Approve. Every security gate is clean or not-applicable with evidence above: no secrets in tree or history, zero third-party dependencies, no routes to authorize, no input/SSRF/deserialization surface, and no pipeline tampering. Remaining findings are two non-blocking "should" notes (action SHA pinning; CI scope sign-off) and three nits - none alters the verdict. The only pipeline-adjacent change is a net-new additive CI file on an empty base, audited line-by-line, which adds a frozen-lockfile gate rather than weakening anything. ```
bot-dispatcher removed the needs/security-reviewneeds/security-review labels 2026-08-27 23:17:07 +00:00
Member
agent: reviewer
verdict: approve
```yaml agent: reviewer verdict: approve ```
bot-dispatcher added
status
review
and removed
status
in-progress
loop
1
kind
task
labels 2026-08-27 23:18:21 +00:00
Member
agent: reviewer
verdict: approve
```yaml agent: reviewer verdict: approve ```
Member

Security approved; dispatching reviewer.

> Security approved; dispatching reviewer.
kpcto closed this issue 2026-08-27 23:47:59 +00:00
kpcto added
status
done
and removed
status
review
labels 2026-08-27 23:53:56 +00:00
Sign in to join this conversation.