Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 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
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
# pnpm version comes from the package.json "packageManager" field
# (pnpm 10+), which is required to read `overrides` from
# pnpm-workspace.yaml consistently with the committed lockfile.
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
Expand Down Expand Up @@ -55,7 +55,7 @@ jobs:
with:
ref: ${{ github.event.pull_request.head.sha || github.sha }}
persist-credentials: false
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
Expand Down
114 changes: 102 additions & 12 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
with:
fetch-depth: 0
- name: Set up pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down Expand Up @@ -91,7 +91,8 @@ jobs:
mv "$package_file" release/
- name: Install hash-locked Office dependencies
working-directory: office
run: python -m pip install --require-hashes --only-binary=:all: -r requirements-ci.txt
run: |
python -m pip install --require-hashes --only-binary=:all: -r requirements-ci.txt
- name: Verify Office dependency consistency
working-directory: office
run: python -m pip check
Expand Down Expand Up @@ -121,11 +122,79 @@ jobs:
assert any(name.endswith('.dist-info/licenses/LICENSE') for name in names)
PY
mv dist/*.whl ../release/
- name: Install Cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
with:
cosign-release: 'v3.0.6'
- name: Install signature-verified Syft
run: |
set -euo pipefail
syft_installer="$RUNNER_TEMP/syft-install.sh"
curl --fail --silent --show-error --location \
--proto '=https' \
--output "$syft_installer" \
https://raw.githubusercontent.com/anchore/syft/16223e6dd7893fe578787658ceb876257483d404/install.sh
mkdir -p "$RUNNER_TEMP/syft-bin"
DOWNLOAD_TAG_INSTALL_SCRIPT=false \
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 exact-package release SBOMs
run: |
set -euo pipefail
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 packageMetadata = JSON.parse(readFileSync('package.json', 'utf8'));
const officeMetadata = readFileSync('office/pyproject.toml', 'utf8');
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.');
}

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 > SHA256SUMS
sha256sum -- *.tgz *.whl *.spdx.json > SHA256SUMS
- name: Transfer exact release artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
Expand All @@ -152,7 +221,7 @@ jobs:
ref: ${{ github.sha }}
persist-credentials: false
- name: Set up pnpm
uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6.0.10
- name: Set up Node.js
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
Expand Down Expand Up @@ -237,7 +306,7 @@ jobs:
- name: Verify bounded local release artifact set
run: |
set -euo pipefail
expected_asset_count=3
expected_asset_count=5
mapfile -t local_entries < <(
find release -mindepth 1 -maxdepth 1 -printf '%f\n' | LC_ALL=C sort
)
Expand All @@ -254,8 +323,10 @@ jobs:
|| ${#local_assets[@]} -ne $expected_asset_count \
|| ${#npm_assets[@]} -ne 1 \
|| ${#wheel_assets[@]} -ne 1 \
|| ! -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, 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 @@ -264,15 +335,32 @@ jobs:
subject-path: |
release/*.tgz
release/*.whl
release/editor-package.spdx.json
release/office-package.spdx.json
release/SHA256SUMS
- name: Attest editor package with matching SBOM
uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0
with:
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/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
gh attestation verify "$artifact" \
--repo "$GITHUB_REPOSITORY" \
--predicate-type https://spdx.dev/Document/v2.3
done
- name: Prepare draft GitHub release
env:
GH_TOKEN: ${{ github.token }}
Expand Down Expand Up @@ -304,7 +392,7 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
expected_asset_count=3
expected_asset_count=5
mapfile -t local_entries < <(
find release -mindepth 1 -maxdepth 1 -printf '%f\n' | LC_ALL=C sort
)
Expand All @@ -321,8 +409,10 @@ jobs:
|| ${#local_assets[@]} -ne $expected_asset_count \
|| ${#npm_assets[@]} -ne 1 \
|| ${#wheel_assets[@]} -ne 1 \
|| ! -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, 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 @@ -414,7 +504,7 @@ jobs:
fi

gh release verify "$GITHUB_REF_NAME" --repo "$GITHUB_REPOSITORY"
for artifact in release/*.tgz release/*.whl 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 @@ -600,7 +690,7 @@ jobs:
process.exit(2);
}
process.stdout.write(url.origin);
NODE
NODE
)" || {
echo "::error::npm dist.tarball must stay on the canonical registry.npmjs.org HTTPS origin."
exit 1
Expand Down Expand Up @@ -646,4 +736,4 @@ jobs:
done

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

on:
push:
branches:
- feat/writing-diagnostics-assurance
pull_request:
paths:
- 'src/components/**'
- 'src/workflowExactHead.test.ts'
- 'src/releaseArtifactSbomContract.test.ts'
- 'tests/browser/**'
- '.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.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, 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/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.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.sha }}
run: >-
pnpm --dir tests/browser exec playwright test
specs/writing-diagnostics.browser.spec.ts
--config playwright.config.ts
43 changes: 33 additions & 10 deletions .github/workflows/writing-diagnostics-collaboration-tdd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,27 +25,50 @@ jobs:
with:
ref: ${{ github.sha }}
persist-credentials: false
- uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8
- 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 collaborative writing-diagnostic parity tests
run: >-
pnpm exec vitest run
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.test.tsx
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.race.test.tsx
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.coverage.test.tsx
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.boundary.test.tsx
--pool=forks
--maxWorkers=1
run: |
set -euo pipefail
output_file="$(mktemp)"
trap 'rm -f "$output_file"' EXIT
set +e
pnpm exec vitest run \
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.test.tsx \
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.race.test.tsx \
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.coverage.test.tsx \
src/collaboration/CollaborativeCwlEditor.writingDiagnostics.boundary.test.tsx \
--pool=forks \
--maxWorkers=1 2>&1 | tee "$output_file"
test_status=${PIPESTATUS[0]}
set -e
if grep -Fq 'not wrapped in act' "$output_file"; then
echo "::error::Focused collaborative diagnostics emitted a React act warning."
exit 1
fi
exit "$test_status"
- name: Typecheck collaborative writing-diagnostic contracts
run: pnpm typecheck
- name: Run complete production coverage gate
env:
NODE_OPTIONS: --max-old-space-size=6144
run: pnpm coverage
run: |
set -euo pipefail
output_file="$(mktemp)"
trap 'rm -f "$output_file"' EXIT
set +e
pnpm coverage 2>&1 | tee "$output_file"
test_status=${PIPESTATUS[0]}
set -e
if grep -Fq 'not wrapped in act' "$output_file"; then
echo "::error::Production coverage emitted a React act warning."
exit 1
fi
exit "$test_status"
- name: Build all package entrypoints
run: pnpm build
- name: Verify isolated packed-package consumers
Expand Down
Loading