fix(m08): add safe product fences #680

Merged
pdurlej merged 1 commit from codex/m08-safe-bug-batch into main 2026-06-02 07:35:47 +02:00
Collaborator

Canary status: missing - fire canary 3+3 manually before merge

Summary

This PR is the M08 safe bug/product batch. It keeps the scope plan-only and read-only for runtime systems: no live deploy, no live Postgres apply, no issue/comment writer, and no runtime mutation.

Closes #646.
Closes #634.
Closes #290 for the static/data-contract dashboard slice; live route activation and ingestion remain explicitly out of scope.

Canary Context Pack

Product story

M08 needs safer product/runtime follow-through before deeper Iskra/OpenClaw work: user-facing errors should not leak raw tool paths, OpenClaw deploys should not be mistaken for activation, and the 8 bogactw dashboard needs a concrete data contract before UI/runtime wiring.

What changed

  • Sanitized Things/vault artifact write failures so raw write errors and paths do not become user-facing output.
  • Disabled live chown/chmod from the Things sync worker path; ownership must be prepared outside the worker.
  • Added an OpenClaw activation receipt fence to validate_deploy_plan.py and the vps1000 deploy workflow.
  • Added the bogactw.v0 JSON schema, sanitized sample fixture, and runbook for the static dashboard data contract.

Why it changed

Claude flagged these as the safe M08 batch: fix the P1 leak class, prevent build-vs-activate confusion, and land a first static/product slice without live deployment.

Files touched

  • .forgejo/workflows/deploy-vps1000.yml
  • control-plane/platformctl/ci/validate_deploy_plan.py
  • control-plane/platformctl/tests/test_forgejo_ci_scripts_contract.py
  • scripts/iskra-things-sync/iskra_things_sync.py
  • tests/test_iskra_things_sync_contract.py
  • schema/bogactw.schema.json
  • fixtures/bogactw-sample.json
  • tests/test_bogactw_contract.py
  • runbooks/deploy-vps1000.md
  • runbooks/iskra-8-bogactw-dashboard.md
  • modules/iskra-things-sync/runbook.md

Relevant context

  • docs/specs/iskra-8-bogactw-dashboard-v0/03-tasks.md
  • state/L4/rfc-decisions.json
  • runbooks/deploy-vps1000.md
  • modules/iskra-things-sync/runbook.md

Runtime evidence

No runtime mutation was performed. Local verification:

  • uv run pytest ../tests/test_iskra_things_sync_contract.py ../tests/test_bogactw_contract.py platformctl/tests/test_forgejo_ci_scripts_contract.py -> 75 passed
  • PYTHONPATH=control-plane uv run --project control-plane python -m platformctl.cli validate all --json -> exitCode 0
  • python3 -m py_compile scripts/iskra-things-sync/iskra_things_sync.py control-plane/platformctl/ci/validate_deploy_plan.py -> passed
  • git diff --check -> clean

Known constraints

The 8 bogactw work is the static/data-contract slice only. It does not add the live dashboard route, Obsidian ingestion, Iskra memory write-back, or any automatic notification.

Explicit out-of-scope

  • Live deploys
  • Runtime apply
  • Live Postgres migration
  • Obsidian ingestion
  • Signal delivery changes beyond sanitized error surfaces
  • Issue/comment writers

Requested decision

Review and merge if the safe fences are acceptable.

Merge blockers

  • Any raw secret/path leakage in failure output
  • Any live deploy/runtime mutation path
  • Any activation receipt path that can claim deployed without smoke pass

Spec sources read

  • scripts/iskra-things-sync/iskra_things_sync.py - Things/vault write path
  • tests/test_iskra_things_sync_contract.py - regression coverage
  • control-plane/platformctl/ci/validate_deploy_plan.py - deploy plan validator
  • control-plane/platformctl/tests/test_forgejo_ci_scripts_contract.py - CI contract coverage
  • runbooks/deploy-vps1000.md - deploy policy
  • modules/iskra-things-sync/runbook.md - Things worker policy
  • docs/specs/iskra-8-bogactw-dashboard-v0/03-tasks.md - dashboard data-contract scope
  • state/L4/rfc-decisions.json - existing value-area code contract
Canary status: missing - fire canary 3+3 manually before merge ## Summary This PR is the M08 safe bug/product batch. It keeps the scope plan-only and read-only for runtime systems: no live deploy, no live Postgres apply, no issue/comment writer, and no runtime mutation. Closes #646. Closes #634. Closes #290 for the static/data-contract dashboard slice; live route activation and ingestion remain explicitly out of scope. ## Canary Context Pack ### Product story M08 needs safer product/runtime follow-through before deeper Iskra/OpenClaw work: user-facing errors should not leak raw tool paths, OpenClaw deploys should not be mistaken for activation, and the 8 bogactw dashboard needs a concrete data contract before UI/runtime wiring. ### What changed - Sanitized Things/vault artifact write failures so raw write errors and paths do not become user-facing output. - Disabled live `chown`/`chmod` from the Things sync worker path; ownership must be prepared outside the worker. - Added an OpenClaw activation receipt fence to `validate_deploy_plan.py` and the vps1000 deploy workflow. - Added the `bogactw.v0` JSON schema, sanitized sample fixture, and runbook for the static dashboard data contract. ### Why it changed Claude flagged these as the safe M08 batch: fix the P1 leak class, prevent build-vs-activate confusion, and land a first static/product slice without live deployment. ### Files touched - `.forgejo/workflows/deploy-vps1000.yml` - `control-plane/platformctl/ci/validate_deploy_plan.py` - `control-plane/platformctl/tests/test_forgejo_ci_scripts_contract.py` - `scripts/iskra-things-sync/iskra_things_sync.py` - `tests/test_iskra_things_sync_contract.py` - `schema/bogactw.schema.json` - `fixtures/bogactw-sample.json` - `tests/test_bogactw_contract.py` - `runbooks/deploy-vps1000.md` - `runbooks/iskra-8-bogactw-dashboard.md` - `modules/iskra-things-sync/runbook.md` ### Relevant context - `docs/specs/iskra-8-bogactw-dashboard-v0/03-tasks.md` - `state/L4/rfc-decisions.json` - `runbooks/deploy-vps1000.md` - `modules/iskra-things-sync/runbook.md` ### Runtime evidence No runtime mutation was performed. Local verification: - `uv run pytest ../tests/test_iskra_things_sync_contract.py ../tests/test_bogactw_contract.py platformctl/tests/test_forgejo_ci_scripts_contract.py` -> 75 passed - `PYTHONPATH=control-plane uv run --project control-plane python -m platformctl.cli validate all --json` -> exitCode 0 - `python3 -m py_compile scripts/iskra-things-sync/iskra_things_sync.py control-plane/platformctl/ci/validate_deploy_plan.py` -> passed - `git diff --check` -> clean ### Known constraints The 8 bogactw work is the static/data-contract slice only. It does not add the live dashboard route, Obsidian ingestion, Iskra memory write-back, or any automatic notification. ### Explicit out-of-scope - Live deploys - Runtime apply - Live Postgres migration - Obsidian ingestion - Signal delivery changes beyond sanitized error surfaces - Issue/comment writers ### Requested decision Review and merge if the safe fences are acceptable. ### Merge blockers - Any raw secret/path leakage in failure output - Any live deploy/runtime mutation path - Any activation receipt path that can claim deployed without smoke pass ## Spec sources read - `scripts/iskra-things-sync/iskra_things_sync.py` - Things/vault write path - `tests/test_iskra_things_sync_contract.py` - regression coverage - `control-plane/platformctl/ci/validate_deploy_plan.py` - deploy plan validator - `control-plane/platformctl/tests/test_forgejo_ci_scripts_contract.py` - CI contract coverage - `runbooks/deploy-vps1000.md` - deploy policy - `modules/iskra-things-sync/runbook.md` - Things worker policy - `docs/specs/iskra-8-bogactw-dashboard-v0/03-tasks.md` - dashboard data-contract scope - `state/L4/rfc-decisions.json` - existing value-area code contract
fix(m08): add safe product fences
All checks were successful
canary-required / collect-diff (pull_request) Successful in 4s
infra-docs-drift / docs-drift (pull_request) Successful in 4s
pyfallow / Pyfallow gate (control-plane) (pull_request) Successful in 15s
python-ci / Python 3.12 (pull_request) Successful in 36s
platformctl plan / auto-apply scope (pull_request) Successful in 17s
python-ci / Python 3.11 (pull_request) Successful in 35s
python-ci / Python 3.13 (pull_request) Successful in 36s
workflow-lint / lint (pull_request) Successful in 4s
canary-required / canary (pull_request) Successful in 13s
base-is-main / guard (pull_request) Successful in 1s
patchwarden-pr-sanity / collect-diff (pull_request) Successful in 3s
patchwarden-client-dry-run / dry-run (pull_request) Successful in 17s
patchwarden-client-dry-run / collect-diff (pull_request) Successful in 3s
patchwarden-pr-sanity / sanity (pull_request) Successful in 5m17s
7c6269d144
Author
Collaborator

Patchwarden PR sanity

  • Status: advisory_findings
  • PR: 680
  • Commit: 7c6269d1442834fc6da97ec153e9eabd80a4608a
  • Security-sensitive label: present
  • Authority: advisory model review plus deterministic blockers only
  • 3+3 canary: still alive; this does not replace it

Deterministic findings

  • info sensitive-path-touched Sensitive path touched — .forgejo/workflows/deploy-vps1000.yml
    • Evidence: .forgejo/workflows/deploy-vps1000.yml
    • Next: Route through the existing 3+3/risk-tier process; model review remains advisory.
  • info sensitive-path-touched Sensitive path touched — schema/bogactw.schema.json
    • Evidence: schema/bogactw.schema.json
    • Next: Route through the existing 3+3/risk-tier process; model review remains advisory.

Model reviewers

global-glm / glm-5.1:cloud

  • Status: ok
  • Verdict: OK
  • Findings: none

global-deepseek / deepseek-v4-pro:cloud

  • Status: ok

  • Verdict: NOT_OK

  • high Incomplete sanitization of vault artifact write failures

    • Evidence: scripts/iskra-things-sync/iskra_things_sync.py: write_receiptcallswrite_vault_text(sanitized) thenmark_vault_file(unsanitized).mark_vault_fileperformsos.utime(path, None) which can raise OSError containing the raw path. Th
    • Next: Wrap mark_vault_file in a try/except that raises VaultArtifactWriteError or sanitize the error in try_write_receipt before logging.
  • medium Activation receipt can be forged by workflow dispatcher

    • Evidence: .forgejo/workflows/deploy-vps1000.yml accepts activation_receiptas a user-supplied input string.control-plane/platformctl/ci/validate_deploy_plan.py loads and trusts this JSON without any cryptographic signature or provenance check. A
    • Next: Generate the activation receipt automatically in a prior CI job (e.g., smoke test) and pass it as an artifact or signed payload. Alternatively, add a signature verification step using a known key.
  • low Breaking change in iskra-things-sync may cause permission errors in existing environments

    • Evidence: scripts/iskra-things-sync/iskra_things_sync.py: make_vault_sync_visibleno longer performschown/chmod. If the script is run without pre-configured directory ownership, subsequent writes may fail with permission errors (now sanitized,
    • Next: Add a pre-flight check in the script that verifies the vault directory is writable and emits a clear warning if ownership appears misconfigured, or provide a migration script.

redteam / kimi-k2.6:cloud

  • Status: ok

  • Verdict: NOT_OK

  • blocker Workflow input interpolation allows shell injection and arbitrary file overwrite

    • Evidence: .forgejo/workflows/deploy-vps1000.yml introduces activation_receipt input (lines 26-29) and interpolates it directly into a bash array: activation_args=(--activation-receipt \"${{ inputs.activation_receipt }}\") which is then expanded into
    • Next: Remove direct expression interpolation from the run block. Pass the value through the env block (env: ACTIVATION_RECEIPT: ${{ inputs.activation_receipt }}) and reference $ACTIVATION_RECEIPT inside the shell script.

Policy notes

  • GLM 5.1 + DeepSeek V4 Pro are the operator-required model mix for this bot.
  • Optional red-team model is enabled only when PLATFORMCTL_PR_SANITY_REDTEAM_MODEL is configured.
  • Auto-merge is not enabled here.
<!-- patchwarden-pr-sanity:pdurlej/platform:PR-680 --> # Patchwarden PR sanity - Status: `advisory_findings` - PR: `680` - Commit: `7c6269d1442834fc6da97ec153e9eabd80a4608a` - Security-sensitive label: `present` - Authority: advisory model review plus deterministic blockers only - 3+3 canary: still alive; this does not replace it ## Deterministic findings - **`info` `sensitive-path-touched`** Sensitive path touched — `.forgejo/workflows/deploy-vps1000.yml` - Evidence: `.forgejo/workflows/deploy-vps1000.yml` - Next: Route through the existing 3+3/risk-tier process; model review remains advisory. - **`info` `sensitive-path-touched`** Sensitive path touched — `schema/bogactw.schema.json` - Evidence: `schema/bogactw.schema.json` - Next: Route through the existing 3+3/risk-tier process; model review remains advisory. ## Model reviewers ### `global-glm` / `glm-5.1:cloud` - Status: `ok` - Verdict: `OK` - Findings: none ### `global-deepseek` / `deepseek-v4-pro:cloud` - Status: `ok` - Verdict: `NOT_OK` - **`high`** Incomplete sanitization of vault artifact write failures - Evidence: `scripts/iskra-things-sync/iskra_things_sync.py: `write_receipt` calls `write_vault_text` (sanitized) then `mark_vault_file` (unsanitized). `mark_vault_file` performs `os.utime(path, None)` which can raise OSError containing the raw path. Th` - Next: Wrap `mark_vault_file` in a try/except that raises `VaultArtifactWriteError` or sanitize the error in `try_write_receipt` before logging. - **`medium`** Activation receipt can be forged by workflow dispatcher - Evidence: `.forgejo/workflows/deploy-vps1000.yml accepts `activation_receipt` as a user-supplied input string. `control-plane/platformctl/ci/validate_deploy_plan.py` loads and trusts this JSON without any cryptographic signature or provenance check. A` - Next: Generate the activation receipt automatically in a prior CI job (e.g., smoke test) and pass it as an artifact or signed payload. Alternatively, add a signature verification step using a known key. - **`low`** Breaking change in iskra-things-sync may cause permission errors in existing environments - Evidence: `scripts/iskra-things-sync/iskra_things_sync.py: `make_vault_sync_visible` no longer performs `chown`/`chmod`. If the script is run without pre-configured directory ownership, subsequent writes may fail with permission errors (now sanitized,` - Next: Add a pre-flight check in the script that verifies the vault directory is writable and emits a clear warning if ownership appears misconfigured, or provide a migration script. ### `redteam` / `kimi-k2.6:cloud` - Status: `ok` - Verdict: `NOT_OK` - **`blocker`** Workflow input interpolation allows shell injection and arbitrary file overwrite - Evidence: `.forgejo/workflows/deploy-vps1000.yml introduces activation_receipt input (lines 26-29) and interpolates it directly into a bash array: activation_args=(--activation-receipt \"${{ inputs.activation_receipt }}\") which is then expanded into ` - Next: Remove direct expression interpolation from the run block. Pass the value through the env block (env: ACTIVATION_RECEIPT: ${{ inputs.activation_receipt }}) and reference $ACTIVATION_RECEIPT inside the shell script. ## Policy notes - GLM 5.1 + DeepSeek V4 Pro are the operator-required model mix for this bot. - Optional red-team model is enabled only when `PLATFORMCTL_PR_SANITY_REDTEAM_MODEL` is configured. - Auto-merge is not enabled here.
pdurlej deleted branch codex/m08-safe-bug-batch 2026-06-02 07:35:48 +02:00
Sign in to join this conversation.
No reviewers
No labels
W6d-automerge-calibration
agent/claude-code
agent/codex
agent/hermes
agent/iskra
agent/ollama
agent/patchwarden
automerge-candidate
class/security-sensitive
cutover-gate
dependency/blocked
dependency/blocks-others
dependency/cross-repo
dependency/needs-confirmation
domain:agents
domain:ci
domain:docs
domain:forgejo
domain:infra
domain:memory
domain:runtime
domain:signal
domain:ux
flow/architecture
flow/blocked
flow/deployed
flow/done
flow/implementation
flow/intake
flow/maintained
flow/observed
flow/ready
flow/refining
flow/retired
flow/review
iterating
judge/codex-candidate
judge/hermes-candidate
judge/low-confidence
judge/needs-refinement
judge/operator-needed
judge/p0
judge/p1
judge/p2
judge/p3
judge/park
judge/patchwarden-candidate
judge/stale-priority
kind/adr
kind/bug
kind/chore
kind/feature
kind/infra
kind/ops
kind/refactor
kind/research
large-impact
merge/auto
merge/manual
merge/manual-dependency-conflict
merge/manual-failing-tests
merge/manual-merge-conflict
merge/manual-missing-review
merge/manual-operator-preference
merge/manual-red-zone
merge/manual-security-sensitive
merge/manual-unclear-scope
merge/manual-unknown
meta
mode:operator-only
mode:patchwarden-iskra-approved
mode:safe-auto
needs-operator-decision
needs-triage
not-ready
observed/erroring
observed/needs-followup
observed/pending
observed/retire-candidate
observed/unused
observed/used
operator-emotional
owner-attention
phase/02
phase/03
priority:p0
priority:p1
priority:p2
priority:p3
proposed
ready-for-agent
ready-for-operator
recovery
review:claude-reviewed
review:codex-reviewed
review:dziadek-reviewed
review:needs-human
risk/exposure
risk/process
risk/product
risk/runtime
safety:external-write
safety:no-prod-mutation
safety:prod-impact
safety:secret-touch
size/large
size/medium
size/small
size/tiny
size/unknown
source/adr
source/agent-generated
source/manual
source/operator-chat
source/voice-note
status:blocked
status:codex-ready
status:merged:pending-evidence
status:needs-evidence
status:operator-needed
status:parked
tier/full
tier/lite
tier/stacked
tier:0-platform-substrate
tier:1-iskra-value-layer
tier:2-tools-products-modules
type:bug
type:chore
type:docs
type:feat
type:policy
type:research
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
pdurlej/platform!680
No description provided.