Skip to content

Commit 6a0bbaa

Browse files
committed
Merge remote-tracking branch 'origin/main' into release-next
# Conflicts: # scripts/spec-word-budgets.json
2 parents f383565 + 33804cb commit 6a0bbaa

31 files changed

Lines changed: 1159 additions & 875 deletions

‎.github/audit/ci-and-secrets.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ Delegate only by these streams (`.github/audit/_preamble.md` -> "Work streams").
3030

3131
- `actions` — `docs/specs/security-ci.md`: "GitHub Actions Policies", "Automated Maintainer (tend)".
3232
- `releases` — `docs/specs/security-ci.md`: "Hosted Deployments", "VS Code Extension Releases", "Desktop Releases".
33-
- `audit` — `docs/specs/security-audit.md`: "Schedule and gate", "Deterministic checks", "Skipping an unchanged audit", "Domains", "Orchestration", "Outcomes and reporting", "Findings", "Embargo", "Findings ledger", "Disclosure", "Environment and `AUDIT_PAT`", "Canary recall".
33+
- `audit` — `docs/specs/security-audit.md`: "Schedule and gate", "Deterministic checks", "Skipping an unchanged audit", "Domains", "Orchestration", "Outcomes and reporting", "Findings", "Embargo", "Findings ledger", "Disclosure", "Environment and `AUDIT_PAT`", "Canary recall", "Red team".
3434
- `qualitative` — the qualitative pass below, once, over the whole of this domain's scope.
3535

3636
## Qualitative pass
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: codex-audit-report
2+
3+
# Publishes the red team's report (docs/specs/security-audit.md -> "Red team"):
4+
# what a maintainer's `scripts/security-audit-local.sh --engine codex` run
5+
# computed, typed in as dispatch inputs. Nothing here runs a model or reads a
6+
# secret, and nothing here gates a release: release.yml waits on
7+
# security-audit.yaml alone. The inputs are non-secret by construction —
8+
# computed verdicts and counts, never a finding — and
9+
# `scripts/security-audit-public-body.mjs` checks each against its pattern,
10+
# and the counts against the CI canary run they share seeds with, before it
11+
# posts anything.
12+
on:
13+
workflow_dispatch:
14+
inputs:
15+
commit:
16+
description: "The commit on main the Codex run audited (40-hex)"
17+
type: string
18+
required: true
19+
model:
20+
description: "The Codex model the run used"
21+
type: string
22+
required: true
23+
default: gpt-6-sol
24+
verdicts:
25+
description: "Each domain's computed verdict: `domain=PASS|FAIL|INCONCLUSIVE …`; empty for a canary alone"
26+
type: string
27+
default: ""
28+
canary_run:
29+
description: "The CI canary run whose key seeded the Codex canary; empty for verdicts alone"
30+
type: string
31+
default: ""
32+
canary_seeded:
33+
description: "Seeds applied"
34+
type: string
35+
default: ""
36+
canary_caught:
37+
description: "Seeds Codex caught"
38+
type: string
39+
default: ""
40+
canary_either:
41+
description: "Seeds Claude or Codex caught"
42+
type: string
43+
default: ""
44+
canary_unfinished:
45+
description: "Codex domains that left no finished report"
46+
type: string
47+
default: ""
48+
49+
run-name: codex-audit-report (advisory, not an audit)
50+
51+
# Each job declares its own.
52+
permissions: {}
53+
54+
jobs:
55+
publish:
56+
runs-on: ubuntu-latest
57+
timeout-minutes: 10
58+
# `issues: write` for the one comment on the status issue; `actions: read`
59+
# to read the CI canary run and download its `canary-recall`.
60+
permissions:
61+
contents: read
62+
issues: write
63+
actions: read
64+
steps:
65+
- name: Refuse any ref but main
66+
run: |
67+
[ "$GITHUB_REF" = refs/heads/main ] && exit 0
68+
echo "::error::A red-team report publishes from main only."
69+
exit 1
70+
71+
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
72+
with:
73+
fetch-depth: 1
74+
persist-credentials: false
75+
76+
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
77+
with:
78+
node-version-file: package.json
79+
80+
# Inputs reach the builder through the environment, never interpolated
81+
# into the script. It refuses a dispatch by anyone but an admin.
82+
- name: Publish the red-team report
83+
env:
84+
GH_TOKEN: ${{ github.token }}
85+
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
86+
COMMIT: ${{ inputs.commit }}
87+
MODEL: ${{ inputs.model }}
88+
VERDICTS: ${{ inputs.verdicts }}
89+
CANARY_RUN: ${{ inputs.canary_run }}
90+
CANARY_SEEDED: ${{ inputs.canary_seeded }}
91+
CANARY_CAUGHT: ${{ inputs.canary_caught }}
92+
CANARY_EITHER: ${{ inputs.canary_either }}
93+
CANARY_UNFINISHED: ${{ inputs.canary_unfinished }}
94+
run: |
95+
mkdir -p "$RUNNER_TEMP/codex-recall"
96+
node scripts/security-audit-public-body.mjs --engine codex \
97+
--date "$(date -u +%Y-%m-%dT%H:%MZ)" --run-url "$RUN_URL" \
98+
--commit "$COMMIT" --model "$MODEL" --verdicts "$VERDICTS" \
99+
--canary-run "$CANARY_RUN" --canary-seeded "$CANARY_SEEDED" \
100+
--canary-caught "$CANARY_CAUGHT" --canary-either "$CANARY_EITHER" \
101+
--canary-unfinished "$CANARY_UNFINISHED" \
102+
--record "$RUNNER_TEMP/codex-recall/codex-recall.json"
103+
104+
# The counts website/scripts/generate-canary-recall.js reads beside the
105+
# CI canary run's own `canary-recall`.
106+
- name: Upload the red-team recall
107+
if: inputs.canary_run != ''
108+
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
109+
with:
110+
name: codex-recall
111+
path: ${{ runner.temp }}/codex-recall/codex-recall.json
112+
retention-days: 90
113+
if-no-files-found: error

‎docs/specs/deploy.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ Source of truth: `create_release` in `scripts/sign-and-deploy.sh`; `publish-vsco
2121

2222
**Must ship a desktop release that carries, or changes, the one-time link version only after Hosted production serves that version** — its rendezvous routes and its `/connect/` page (`docs/specs/one-time.md` -> "Link"): run `.github/workflows/hosted-production.yml` first and confirm its live verification passed, `oneTimeSmoke` included. **Hosted must never stop serving a link version a shipped Burrow emits.**
2323

24+
A release that changes remote control or Hosted runs the red team first (`docs/specs/security-audit.md` -> "Red team").
25+
2426
Human-driven, in order:
2527

2628
1. **Start a release branch** — from the main checkout, `wt switch --create release-next --base main`, then `pnpm install` in the new worktree; every later step runs there. **A release reaches `main` through one PR, never a direct push.**

‎docs/specs/dor-tools-builtin.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ Source of truth: `saveText` / `StorePath` in `dor-tools-builtin/src/editor-route
4444
`.md` and `.markdown` open in the bundled MDXEditor page; `.mdx` and other text stay in Monaco. Saving, reloading, and dirty reports follow [Editing files](#editing-files).
4545

4646
- **Must resolve the viewer's direct `lexical` and `@lexical/link` imports to the same installed modules MDXEditor uses** (rationale).
47-
- **Must support GFM tables, task lists, frontmatter, code blocks, fenced `mermaid` diagrams, and a whole-document source mode**, which opens with the error when the rich editor cannot parse a file. Mermaid stays on 11 (rationale).
48-
- **Must keep HTML comments verbatim and save with one final newline, the file's majority bullet and thematic-break marker, and unpadded tables**; the rest follows MDXEditor's serialization. Its normalization of loaded text is not an edit (rationale).
47+
- **Must support GFM tables, task lists, frontmatter, code blocks, fenced `mermaid` diagrams, and a whole-document source mode**, which opens with the error when the rich editor cannot parse a file. **Must let source edits remain dirty and saveable after a parse error, and allow repaired source back into rich text.** Mermaid stays on 11 (rationale).
48+
- **Must keep HTML comments verbatim and save with one final newline, the file's majority bullet and thematic-break marker, and unpadded tables**. **Must retain simple standalone bracket labels, encode literal angle brackets in text as entities, and preserve recognized headings' existing blank-line choice**, with new or renamed headings following the majority style; ambiguous Markdown keeps the serializer's escapes. The rest follows MDXEditor's serialization. Its normalization of loaded text is not an edit (rationale).
4949
- **Never let document HTML reach the live DOM outside an allowlist** of tags and attributes, `href` limited to `http(s):`, `mailto:`, fragments, and scheme-less paths; saving keeps every original attribute, escaped, and HTML images serialize in an inert document. Mermaid diagrams are the one other path, under mermaid's own sanitizer (`docs/specs/security-local.md` → "Local-file viewer"; rationale).
5050
- **Must serve images on request from regular image-format files at or under the document's canonical directory**, by realpath, under a `sandbox` CSP. Nothing else loads, external URLs included.
5151
- **Never show an image at a size the document does not state**: unsized, it shows pixel for pixel, within the column. A pasted or dropped PNG or JPEG with a recorded scale goes in at its pixel width over that scale (rationale).

‎docs/specs/dor-tools-builtin.rationale.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ MDXEditor 4.3.3 depends on Lexical `^0.48.0`; independent direct bumps to 0.52 i
2222

2323
MDXEditor 4.3 parses `<!-- … -->` and discards it, and trims and re-serializes the whole document on export; without the comment node and style detection, saving a typical README after a one-word edit deleted its comments and rewrote every `-` bullet as `*` (measured 2026-10).
2424

25+
Issue #1254 (2026-10) exposed unconditional bracket escaping, literal angle brackets changing spelling across rich/source imports, and blank lines inserted after every heading. Serializer options keep simple labels and per-heading spacing without retaining a parallel source tree, while entity-encoding text brackets survives MDX JSX parsing. Code and HTML still use their own serializers. MDXEditor also leaves its initial-normalization flag set after a failed import; treating source changes as edits after that failure permits repair and save.
26+
2527
Image sizes live in the document because GitHub shows an `<img>` without a `width` pixel for pixel: a Retina screenshot shown here at its recorded scale but left unsized in the file came out twice as large on GitHub. Writing the width on paste keeps the two renderings alike (2026-10).
2628

2729
Image URLs carry a per-load generation because the browser keeps decoded images by URL: a reload that only remounted the editor still showed an image's old pixels after the file changed on disk (observed live, 2026-10).

0 commit comments

Comments
 (0)