Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
b5126b6
test(diagnostics): require no-fallback and hostile-input assurance
seonghobae Aug 12, 2026
6f550d3
test(diagnostics): require cross-engine browser assurance
seonghobae Aug 12, 2026
1cd03c5
test(diagnostics): include cross-engine and mobile browser projects
seonghobae Aug 12, 2026
23216d8
test(diagnostics): type browser assurance harness
seonghobae Aug 12, 2026
8817f8b
ci(diagnostics): add browser assurance TDD lane
seonghobae Aug 12, 2026
38103c8
test(diagnostics): add public browser diagnostics harness
seonghobae Aug 12, 2026
7dafa56
test(diagnostics): tolerate repeated redacted contract errors
seonghobae Aug 12, 2026
519cb58
fix(diagnostics): focus verified affected text
seonghobae Aug 12, 2026
b7e80b8
ci(release): carry canonical executable workflow
seonghobae Aug 12, 2026
382e9ee
ci(diagnostics): add one-shot review repair
seonghobae Aug 12, 2026
abfeb75
ci(diagnostics): externalize one-shot review patch
seonghobae Aug 12, 2026
e3e4bb5
ci(diagnostics): run one-shot review repair
seonghobae Aug 12, 2026
1a89ce0
ci(diagnostics): correct repeated verification repair anchor
seonghobae Aug 12, 2026
f82300e
ci(diagnostics): rerun corrected review repair
seonghobae Aug 12, 2026
c873d76
ci(diagnostics): correct hostile assertion repair
seonghobae Aug 12, 2026
69cf1fb
ci(diagnostics): rerun bounded review repair
seonghobae Aug 12, 2026
3308f0f
ci(diagnostics): validate one-shot script mutation
seonghobae Aug 12, 2026
267c9a7
ci(diagnostics): remove mutated one-shot scripts safely
seonghobae Aug 12, 2026
d5eab5c
test(release): reject vulnerable pnpm bootstrap
seonghobae Aug 12, 2026
48c59d0
ci(diagnostics): run release bootstrap regression
seonghobae Aug 12, 2026
0361697
fix(release): use repaired pnpm bootstrap
seonghobae Aug 12, 2026
413b3ac
test(security): assert diagnostic payload stays inert
seonghobae Aug 12, 2026
3974796
test(browser): declare harness React runtime deps
seonghobae Aug 12, 2026
ef6aaf5
test(browser): lock isolated React harness deps
seonghobae Aug 12, 2026
393c1a6
ci(diagnostics): remove obsolete self-modifying writer
seonghobae Aug 12, 2026
ca8bfe6
ci(diagnostics): remove obsolete review repair script
seonghobae Aug 12, 2026
49eca24
ci(diagnostics): remove obsolete repair counter
seonghobae Aug 12, 2026
52f6268
test(release): require artifact-specific SBOM provenance
seonghobae Aug 12, 2026
92f4cc4
test(release): execute artifact SBOM contract
seonghobae Aug 12, 2026
cd9440e
test(security): assert hostile explanation before invalidation
seonghobae Aug 12, 2026
6af99b9
test(release): read workflow from repository root
seonghobae Aug 12, 2026
4262224
fix(release): bind SBOMs to exact packages
seonghobae Aug 12, 2026
db73458
fix(ci): inherit pinned package bootstrap
seonghobae Aug 12, 2026
0688db9
test(diagnostics): cover unavailable editor focus
seonghobae Aug 12, 2026
9c0c3ec
test(browser): fail closed on missing diagnostics probe
seonghobae Aug 12, 2026
b69ed82
test(browser): key touch target checks to capability
seonghobae Aug 12, 2026
1ad319c
Merge live diagnostics package base
seonghobae Aug 12, 2026
00b6775
test(ci): require Playwright browser cache contract
seonghobae Aug 12, 2026
6e74a9b
ci(diagnostics): cache exact Playwright browser revisions
seonghobae Aug 12, 2026
bf3a065
fix(diagnostics): preserve focus across selection and dismissal
seonghobae Aug 13, 2026
ccad62d
test(ci): preserve diagnostics workflow hardening across stack
seonghobae Aug 13, 2026
ccd3946
chore(diagnostics): reconcile assurance with current stack
seonghobae Aug 13, 2026
c6c2799
test(ci): inherit current main pnpm bootstrap contract
seonghobae Aug 13, 2026
e4a121a
chore(ci): inherit current main release security contracts
seonghobae Aug 13, 2026
eb63517
test(docs): require canonical writing diagnostics guide
seonghobae Aug 13, 2026
d6cdb5c
docs(diagnostics): satisfy canonical guide contract
seonghobae Aug 19, 2026
b3aa916
docs(diagnostics): index canonical active guide
seonghobae Aug 19, 2026
56af8aa
ci(diagnostics): execute canonical documentation contract
seonghobae Aug 19, 2026
91dfddd
fix(docs): satisfy diagnostics guide vocabulary contract
seonghobae Aug 19, 2026
f9ab67c
test(release): require browser evidence setup headroom
seonghobae Aug 20, 2026
599d2eb
fix(release): give browser evidence finite setup headroom
seonghobae Aug 20, 2026
3e17ac7
Merge current writing-diagnostics package parent into assurance
seonghobae Aug 21, 2026
4bbef62
fix(release): preserve package SBOM contract across stack merge
seonghobae Aug 22, 2026
5835a27
test(ci): require diagnostics assurance exact-head checkout
seonghobae Aug 22, 2026
99157b3
fix(test): preserve safe pnpm action pin oracle
seonghobae Aug 22, 2026
3590261
fix(ci): run diagnostics assurance on exact PR head
seonghobae Aug 22, 2026
c9685a7
Merge current package Semgrep repair into assurance
seonghobae Aug 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 58 additions & 37 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -148,48 +148,62 @@ jobs:
sh "$syft_installer" -v -b "$RUNNER_TEMP/syft-bin" v1.50.0
"$RUNNER_TEMP/syft-bin/syft" version
echo "$RUNNER_TEMP/syft-bin" >> "$GITHUB_PATH"
- name: Generate release SBOM
- name: Generate exact-package release SBOMs
run: |
set -euo pipefail
syft scan dir:. -o spdx-json > release/inkspan.spdx.json
- name: Validate release SBOM
mapfile -t npm_assets < <(
find release -maxdepth 1 -type f -name '*.tgz' -printf '%f\n' | LC_ALL=C sort
)
mapfile -t wheel_assets < <(
find release -maxdepth 1 -type f -name '*.whl' -printf '%f\n' | LC_ALL=C sort
)
if [[ ${#npm_assets[@]} -ne 1 || ${#wheel_assets[@]} -ne 1 ]]; then
echo "::error::SBOM generation requires exactly one npm tarball and one Office wheel."
exit 1
fi
syft scan "release/${npm_assets[0]}" -o spdx-json > release/editor-package.spdx.json
syft scan "release/${wheel_assets[0]}" -o spdx-json > release/office-package.spdx.json
- name: Validate exact-package release SBOMs
run: |
set -euo pipefail
node <<'NODE'
const { readFileSync, statSync } = require('node:fs');

const sbomPath = 'release/inkspan.spdx.json';
const sbom = JSON.parse(readFileSync(sbomPath, 'utf8'));
const packageMetadata = JSON.parse(readFileSync('package.json', 'utf8'));
const officeMetadata = readFileSync('office/pyproject.toml', 'utf8');
if (statSync(sbomPath).size > 16 * 1024 * 1024) {
throw new Error('Release SBOM exceeds the 16 MiB actions/attest input limit.');
}
if (sbom.spdxVersion !== 'SPDX-2.3') {
throw new Error(`Release SBOM must be SPDX-2.3; found ${sbom.spdxVersion ?? 'missing'}.`);
}
if (!Array.isArray(sbom.packages) || sbom.packages.length === 0) {
throw new Error('Release SBOM package inventory must not be empty.');
}
const sbomPackageNames = new Set(sbom.packages.map((pkg) => pkg.name));
if (packageMetadata.name !== '@contextualwisdomlab/cwl-editor') {
throw new Error('Release source has an unexpected editor package identity.');
}
if (!/^name\s*=\s*["']inkspan-office["']\s*$/m.test(officeMetadata)) {
throw new Error('Release source has an unexpected Office package identity.');
}
if (!sbomPackageNames.has(packageMetadata.name)) {
throw new Error('Release SBOM inventory must include the editor package identity.');
}
if (!sbomPackageNames.has('inkspan-office')) {
throw new Error('Release SBOM inventory must include the Office package identity.');

const expectedSboms = [
['release/editor-package.spdx.json', packageMetadata.name],
['release/office-package.spdx.json', 'inkspan-office'],
];
for (const [sbomPath, expectedPackageName] of expectedSboms) {
const sbom = JSON.parse(readFileSync(sbomPath, 'utf8'));
if (statSync(sbomPath).size > 16 * 1024 * 1024) {
throw new Error(`${sbomPath} exceeds the 16 MiB actions/attest input limit.`);
}
if (sbom.spdxVersion !== 'SPDX-2.3') {
throw new Error(`${sbomPath} must be SPDX-2.3; found ${sbom.spdxVersion ?? 'missing'}.`);
}
if (!Array.isArray(sbom.packages) || sbom.packages.length === 0) {
throw new Error(`${sbomPath} package inventory must not be empty.`);
}
const packageNames = new Set(sbom.packages.map((pkg) => pkg.name));
if (!packageNames.has(expectedPackageName)) {
throw new Error(`${sbomPath} must include exact package identity ${expectedPackageName}.`);
}
}
NODE
- name: Generate release checksums
run: |
set -euo pipefail
cd release
sha256sum -- *.tgz *.whl inkspan.spdx.json > SHA256SUMS
sha256sum -- *.tgz *.whl *.spdx.json > SHA256SUMS
- name: Transfer exact release artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
Expand All @@ -204,7 +218,7 @@ jobs:
if: github.repository == 'ContextualWisdomLab/inkspan'
needs: build-release-artifacts
runs-on: ubuntu-24.04
timeout-minutes: 30
timeout-minutes: 60
permissions:
contents: read
env:
Expand Down Expand Up @@ -301,7 +315,7 @@ jobs:
- name: Verify bounded local release artifact set
run: |
set -euo pipefail
expected_asset_count=4
expected_asset_count=5
mapfile -t local_entries < <(
find release -mindepth 1 -maxdepth 1 -printf '%f\n' | LC_ALL=C sort
)
Expand All @@ -318,9 +332,10 @@ jobs:
|| ${#local_assets[@]} -ne $expected_asset_count \
|| ${#npm_assets[@]} -ne 1 \
|| ${#wheel_assets[@]} -ne 1 \
|| ! -f release/inkspan.spdx.json \
|| ! -f release/editor-package.spdx.json \
|| ! -f release/office-package.spdx.json \
|| ! -f release/SHA256SUMS ]]; then
echo "::error::Unexpected local release artifact set; require exactly one *.tgz, one *.whl, inkspan.spdx.json, and SHA256SUMS."
echo "::error::Unexpected local release artifact set; require exactly one *.tgz, one *.whl, editor-package.spdx.json, office-package.spdx.json, and SHA256SUMS."
exit 1
fi
- name: Attest release artifacts
Expand All @@ -329,21 +344,25 @@ jobs:
subject-path: |
release/*.tgz
release/*.whl
release/inkspan.spdx.json
release/editor-package.spdx.json
release/office-package.spdx.json
release/SHA256SUMS
- name: Attest release packages with SBOM
- name: Attest editor package with matching SBOM
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
subject-path: |
release/*.tgz
release/*.whl
sbom-path: release/inkspan.spdx.json
subject-path: release/*.tgz
sbom-path: release/editor-package.spdx.json
- name: Attest Office package with matching SBOM
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
subject-path: release/*.whl
sbom-path: release/office-package.spdx.json
- name: Verify generated attestations
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
for artifact in release/*.tgz release/*.whl release/inkspan.spdx.json release/SHA256SUMS; do
for artifact in release/*.tgz release/*.whl release/editor-package.spdx.json release/office-package.spdx.json release/SHA256SUMS; do
gh attestation verify "$artifact" --repo "$GITHUB_REPOSITORY"
done
for artifact in release/*.tgz release/*.whl; do
Expand Down Expand Up @@ -382,7 +401,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
expected_asset_count=4
expected_asset_count=5
mapfile -t local_entries < <(
find release -mindepth 1 -maxdepth 1 -printf '%f\n' | LC_ALL=C sort
)
Expand All @@ -399,9 +418,10 @@ jobs:
|| ${#local_assets[@]} -ne $expected_asset_count \
|| ${#npm_assets[@]} -ne 1 \
|| ${#wheel_assets[@]} -ne 1 \
|| ! -f release/inkspan.spdx.json \
|| ! -f release/editor-package.spdx.json \
|| ! -f release/office-package.spdx.json \
|| ! -f release/SHA256SUMS ]]; then
echo "::error::Unexpected local release artifact set; require exactly one *.tgz, one *.whl, inkspan.spdx.json, and SHA256SUMS."
echo "::error::Unexpected local release artifact set; require exactly one *.tgz, one *.whl, editor-package.spdx.json, office-package.spdx.json, and SHA256SUMS."
exit 1
fi

Expand Down Expand Up @@ -477,6 +497,7 @@ jobs:
gh release edit "$GITHUB_REF_NAME" \
--repo "$GITHUB_REPOSITORY" \
--draft=false

release_immutable="$(gh release view "$GITHUB_REF_NAME" \
--repo "$GITHUB_REPOSITORY" \
--json isImmutable \
Expand All @@ -492,7 +513,7 @@ jobs:
fi

gh release verify "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY"
for artifact in release/*.tgz release/*.whl release/inkspan.spdx.json release/SHA256SUMS; do
for artifact in release/*.tgz release/*.whl release/editor-package.spdx.json release/office-package.spdx.json release/SHA256SUMS; do
gh release verify-asset "$GITHUB_REF_NAME" "$artifact" \
--repo "$GITHUB_REPOSITORY"
done
Expand Down Expand Up @@ -724,4 +745,4 @@ jobs:
done

echo "::error::Registry publication verification did not converge to the exact artifact digests."
exit 1
exit 1
90 changes: 90 additions & 0 deletions .github/workflows/writing-diagnostics-assurance-tdd.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Writing Diagnostics Assurance TDD

on:
push:
branches:
- feat/writing-diagnostics-assurance
pull_request:
paths:
- 'src/components/**'
- 'src/writingDiagnosticsCanonicalDocumentation.test.ts'
- 'src/workflowExactHead.test.ts'
- 'src/releaseArtifactSbomContract.test.ts'
- 'tests/browser/**'
- 'docs/WRITING_DIAGNOSTICS.md'
- 'docs/README.md'
- '.github/workflows/release.yml'
- '.github/workflows/writing-diagnostics-assurance-tdd.yml'
workflow_dispatch:

permissions:
contents: read

concurrency:
group: writing-diagnostics-assurance-tdd-${{ github.ref }}
cancel-in-progress: true

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
unit-assurance:
runs-on: ubuntu-24.04
timeout-minutes: 20
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- name: Run hostile-input, no-fallback, focus, documentation, release-provenance, and workflow assurance
run: >-
pnpm exec vitest run
src/components/writingDiagnosticsSecurity.test.tsx
src/components/writingDiagnosticsFocus.test.tsx
src/components/WritingDiagnosticsPanel.test.tsx
src/writingDiagnosticsCanonicalDocumentation.test.ts
src/releaseArtifactSbomContract.test.ts
src/workflowExactHead.test.ts
--pool=forks
--maxWorkers=1
- name: Typecheck assurance changes
run: pnpm typecheck

browser-assurance:
name: Writing diagnostics / Playwright 1.62.0
runs-on: ubuntu-24.04
timeout-minutes: 30
env:
PLAYWRIGHT_BROWSERS_PATH: /tmp/inkspan-playwright-browsers
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --dir tests/browser install --frozen-lockfile
- name: Restore exact Playwright browser revisions
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: /tmp/inkspan-playwright-browsers
key: ${{ runner.os }}-playwright-${{ runner.arch }}-${{ hashFiles('tests/browser/pnpm-lock.yaml') }}
- name: Install Playwright revisions pinned by the browser-test lock
run: pnpm --dir tests/browser exec playwright install --with-deps chromium firefox webkit
- name: Run writing-diagnostic browser assurance on exact head
env:
INKSPAN_EXPECTED_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.sha }}
run: >-
pnpm --dir tests/browser exec playwright test
specs/writing-diagnostics.browser.spec.ts
--config playwright.config.ts
1 change: 1 addition & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ This directory is the discoverable index for Inkspan's product, technical, secur
| [`TRD.md`](TRD.md) | Technical invariants, runtime boundaries, failure semantics and release evidence |
| [`CONTRACTS.md`](CONTRACTS.md) | Public package/API/event/schema/plugin/collaboration and host-integration contracts |
| [`package-distribution.md`](package-distribution.md) | Buyer-facing public npm package entrypoints, packaged contents, runtime dependency boundaries, and consumer verification |
| [`WRITING_DIAGNOSTICS.md`](WRITING_DIAGNOSTICS.md) | Active-PR host-owned semantic diagnostics boundary, deterministic revision integrity, privacy, accessibility and rollback contract |
| [`email-output.md`](email-output.md) | Deterministic email fragment/full-document authority, language/direction metadata, accessibility and host-owned transport boundary |
| [`print-output.md`](print-output.md) | Browser print/paged-media presentation, accessibility/fidelity limits, host-owned governed-export boundary, and rollback |
| [`UML.md`](UML.md) | Component, sequence, state and authority-flow diagrams |
Expand Down
Loading