feat(colors): private declarative walking skeleton with atomic publish sink - #568
Conversation
…h sink Private surface (C7c-gated): the private program, WASM consumer, fixtures and mutation/publish contract tests ship only in this private slice; the public surface stays unchanged until gate C7c is intentionally opened. Atomic sink and lifecycle: output bindings leave through one atomic sink (atomic-write.mjs + durability tests); the build -> publish -> verify lifecycle is driven by build-private-program / prepare-npm-package with an exact WASM size budget (check-private-program-wasm-size-budget). Release proof: verify-package-release and the release-contract/provenance tests bind the exact published artifact (tarball inspection, consumer contract, source snapshot, publish contract). Regenerated source attestations: receipt-v1.json + sha256 and the point-support reference-surplus proof + verifier were regenerated and re-pinned to the changed source closure; the chain was re-verified end-to-end. Stage B / local evidence: ci-worker and publish-worker carry caller pins and guard SHAs into the job; generated WASM, build receipts, metadata and local evidence stay git-ignored and are not committed. Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 40 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
WalkthroughДобавлена закрытая private Program для WASM с фиксированным ABI, lifecycle и host handoff. Selection release материализуется и входит в ContentIdentity V8. Сборка, npm tarball, manifest, публикация, browser proof и mutation proof используют канонические проверки, digest и временные бюджеты. ChangesPrivate Program и Core-контракты
Сборка и публикация
CI и контракты
Estimated code review effort: 5 (Critical) | ~120 minutes Sequence Diagram(s)sequenceDiagram
participant CI
participant buildPrivateProgram
participant verifyPackageRelease
participant testPrivateProgramBrowser
participant PrivateProgramConsumer
participant WASM
CI->>buildPrivateProgram: build optimized private Program
buildPrivateProgram->>verifyPackageRelease: provide WASM, receipt and metadata
verifyPackageRelease->>verifyPackageRelease: inspect tarball and create verified snapshot
CI->>testPrivateProgramBrowser: run proof with tarball SHA-256
testPrivateProgramBrowser->>PrivateProgramConsumer: install verified tarball
PrivateProgramConsumer->>WASM: run ABI request
WASM->>PrivateProgramConsumer: return certified result
PrivateProgramConsumer->>testPrivateProgramBrowser: return CSS, receipt and dispose status
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Comment |
…before tests On Linux, replacing an admitted source file before the digest read reused the freed inode (probe: both generations reported dev=2096 ino=1514954, and size/mtime/ctime/birthtime collided within one timestamp tick), so the (dev, ino) check passed and the receipt silently bound the replacement bytes. Admission now captures identity and bytes from one open file description; the read re-verifies both, rejecting any generation whose bytes differ. A same-size replacement regression test locks the class. CI runs npm test before release:verify, so the ignored private WASM did not exist and release-contract tests ENOENT'd. The package test script now runs scripts/ensure-private-program-artifact.mjs first: it reuses an artifact whose build receipt verifies against the current Core source, otherwise performs the canonical build, and fails loudly instead of skipping when the build fails.
The pinned caller worker's dtolnay/rust-toolchain action exports CARGO_INCREMENTAL=0, so the in-process canonical build in ensure-private-program-artifact.mjs correctly failed its strict validator before any test ran. The test prerequisite now spawns the canonical builder as a child process whose environment drops exactly the variables isCanonicalBuildEnvOverride classifies as executor/build overrides - one exported law shared with validateCanonicalBuildEnvironment, which is unchanged and still rejects the same variables when the builder is called directly. Required pins (BINARYEN_*, RUSTUP_HOME, CARGO_HOME, PATH) pass through untouched; the ambient CLI keeps its contact-build behavior and --require-optimizer is the hermetic entrypoint. Tests lock the boundary: override classification, hermetic filtering, preservation of required pins, the filtered environment passing the strict validator unchanged, and direct rejection of CARGO_INCREMENTAL/RUSTFLAGS/NODE_OPTIONS/NODE_PATH. Full npm test passes on a clean Linux checkout with CARGO_INCREMENTAL=0 in the parent environment and the private WASM absent: the child performs the canonical build and all 437 tests pass.
There was a problem hiding this comment.
Actionable comments posted: 20
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/labcolors-core/src/program/attachment.rs (1)
882-951: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueСократите дублирование между
attachиattach_external.Оба метода выполняют одинаковую последовательность:
prepare_attachment_cold, упаковку contract failure вAttachmentCreateFailureV2::Contractиadmit_prepared_stateс одинаковымmap_err. Различаются только границы трейтов и конструктор обёртки. Выделите общий приватный помощник, который принимает функцию-обёртку. Это уменьшит риск расхождения двух путей admission при будущих изменениях контракта.♻️ Предлагаемая структура
impl OwnerV1 { fn attach_with<L, A>( &self, stream_id: u32, authored_emissions: &[AuthoredPointEmissionBindingV1<L::OutputId>], authored_presentations: &[AuthoredPointPresentationBindingV1], family_artifacts: FamilyArtifactBundleV2, sink: L, wrap: impl FnOnce(AttachedProgramStateV1<L::Writer>) -> A, ) -> Result<A, AttachmentCreateFailureV2<L>> where L: UnboundPointSinkWriterV1, { // одна общая cold-подготовка и один общий admission } }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/labcolors-core/src/program/attachment.rs` around lines 882 - 951, Сократите дублирование в методах attach и attach_external, выделив общий приватный помощник attach_with, который выполняет prepare_attachment_cold, преобразует ошибку подготовки в AttachmentCreateFailureV2::Contract и вызывает admit_prepared_state с единым map_err для AttachmentCreateFailureV2::SinkAdmission. Передавайте в помощник функцию wrap для создания соответствующего результата; сохраните требования трейтов и текущие типы обёрток каждого публичного метода.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.github/workflows/ci-worker.yml:
- Around line 831-855: Устраните дублирование таймаутов в job: объявите общий
минутный бюджет рядом с существующими WASM-бюджетами и используйте его в расчёте
remaining вместо литерала 70, а также выведите миллисекундный timeout mutation
из этого же источника для LAB_COLORS_PRIVATE_MUTATION_TIMEOUT_MS. Сохраните
литерал в timeout-minutes и добавьте комментарий, что он должен совпадать с
новым WASM_JOB_TIMEOUT_MINUTES.
In `@crates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.json`:
- Around line 72-118: Добавьте
crates/labcolors-core/src/program/attachment/handoff.rs в PRODUCT_ARTIFACT_PATHS
и соответствующую запись artifacts в receipt с актуальными размером, лицензией и
SHA-256; если файл не должен аттестоваться, вместо этого исключите его из
заявленной области аттестации и согласованно обновите receipt.
In `@crates/labcolors-core/src/private_fixture.rs`:
- Around line 681-687: Разделите пространства значений в
`begin_dispose_status_v1`: возвращайте успешный generation-token со смещением в
зарезервированный диапазон, сохраняя `0` и коды
`PrivateFixtureErrorV1::status()` для ошибок. Обновите `abort_dispose_v1` и
`commit_dispose_v1`, чтобы они снимали это смещение перед сравнением или
использованием внутреннего token; обычные error status должны продолжить
обрабатываться без изменений.
In `@crates/labcolors-core/src/program/attachment/handoff.rs`:
- Around line 446-454: Добавьте краткий комментарий рядом с
`next_handoff_point_sink_epoch_v1`, объясняющий использование
`Ordering::Relaxed`: epoch является лишь уникальным токеном, передаваемым
вызывающему коду по значению, поэтому синхронизация с другими данными не
требуется.
- Around line 125-129: Удалите вариант HandoffPointSinkHostErrorV1::Busy,
поскольку он нигде не создаётся и остаётся мёртвым кодом, либо реализуйте его
полноценное конструирование и обработку во всех соответствующих путях handoff.
In `@packages/colors/package.json`:
- Around line 68-72: Document the local build prerequisites for the scripts in
the package scripts block, including the required Binaryen version/configuration
and pinned rustup toolchain. Explain that these pins are needed for npm run
prepack and for npm test when a valid canonical artifact is unavailable, while
preserving the existing CI and publish workflows.
In `@packages/colors/test/private-program-test-prerequisite.test.mjs`:
- Around line 106-122: Make the parent environment in the test around
hermeticBuildEnvironment explicitly define all required canonical
pins—CARGO_HOME, RUSTUP_HOME, RUST_TOOLCHAIN, and LANG—in addition to the
existing BINARYEN_* and forbidden-variable values, matching the complete setup
used by the nearby positive validator test. Avoid relying on process.env so the
strict canonical-validator assertion is deterministic outside CI.
In `@packages/colors/test/release-contract.test.mjs`:
- Line 1164: Clone PRIVATE_PROGRAM_CANONICAL_BUILD with structuredClone at each
assignment on lines 1164, 1191, and 1250 before passing the values to
validators. Update the build, context.privateProgramBuild.build, and
metadata.build assignments so each receives an independent object, preserving
meaningful deep-equality validation and preventing cross-test mutation.
- Around line 3075-3085: Нормализуйте унаследованное окружение перед
переопределением PATH: в
packages/colors/test/release-contract.test.mjs#L3075-L3085 удалите существующий
ключ пути без учёта регистра, затем установите PATH с fakeBin и pythonBin;
аналогично в packages/colors/test/release-contract.test.mjs#L2510-L2513 удалите
регистронезависимый вариант перед установкой PATH с fakeBin для shell ancestry
guard.
- Around line 3094-3099: Исправьте разбор GITHUB_OUTPUT в построении
verifiedOutputs: замените split("\n") на split(/\r?\n/u) и разбирайте каждую
строку по первому символу "=" с сохранением всего оставшегося значения, включая
дополнительные "="; сохраните текущую структуру Map.
- Around line 1331-1357: Replace the raw byte-pattern scan in the test “the
private Program WASM rejects a shared-memory section mutant” with WASM section
parsing: start after the 8-byte header, decode each section’s LEB128 size, and
advance by its complete payload until locating section ID 5. Use that parsed
memory-section offset for the existing mutant construction, preserving the
current mutation bytes and assertion.
- Around line 3050-3072: Update the Windows setup in the release-contract test
to create a local python3.exe alias in fakeBin, pointing to the executable
returned by sys.executable, before validation runs. Keep fakeBin first in PATH
and retain the existing npm.exe setup; ensure the validator’s python3 lookup
resolves through the new alias instead of asserting python3.exe in the system
Python directory.
- Around line 714-718: Добавьте общий guard для сценариев с symlinkSync: заранее
определяйте поддержку символических ссылок пробным созданием и при EPERM
пропускайте только соответствующий symlink-тест, сохраняя обычный путь проверки
при доступных symlink. Примените guard к вызовам, связанным с linkedResult и
сценариям на строках 924 и 1130–1131; не заменяйте symlink обычным файлом.
In `@packages/colors/test/release-provenance.test.mjs`:
- Around line 28-51: Make the prepack fixture validate that
PREPACK_FIXTURE_SCRIPT_FILES contains every relative script dependency reachable
from prepare-npm-package.mjs and its imported modules. Add this completeness
check around copyPrepackFixture or the related provenance test, while preserving
the intentional atomic-write omission used by the negative guard test, so
missing fixture files fail distinctly from the guard regression.
In `@scripts/build-private-program.mjs`:
- Around line 1138-1149: Вынесите проверку согласованности BINARYEN_ROOT,
BINARYEN_RELEASE и BINARYEN_NODE_SHA256 из buildPrivateProgram и
configuredOptimizer в одну общую функцию с единым текстом ошибки. Вызывайте эту
функцию в обоих местах, сохранив отдельную проверку requireOptimizer для
обязательной настройки оптимизатора.
- Around line 1092-1105: Упростите проверку валидации внутри
validatePrivateProgramBuildReceipt: уберите недостижимое условие
requireOptimizer && toolchain.optimizer === null и проверяйте только наличие
toolchain. Сохраните последующее сравнение ожидаемого дескриптора для отклонения
receipt с неподходящим optimizer.
- Around line 65-70: Wrap the module-level runtime wasm budget loading around
sharedWasmToolchain in the existing fail-based error contract, so missing or
invalid RUNTIME_WASM_BUDGET data produces a typed failure prefixed with “private
Program build:”. Preserve the current parsing and toolchain extraction behavior
on valid input.
In `@scripts/ensure-private-program-artifact.mjs`:
- Around line 55-72: Update verifiedArtifactExists to use the shared
readPrivateProgramBuildReceipt helper instead of directly reading and
JSON-parsing receiptPath, while preserving the existing validation inputs and
failure behavior. This keeps artifact verification aligned with the canonical
receipt parsing used by the release path.
In `@scripts/prepare-npm-package.mjs`:
- Around line 46-57: Remove the local WASM_MAGIC, assertWebAssemblyBinary, and
artifactMetadata definitions from the package preparation flow. Export the
existing assertWasm and artifactMetadata helpers from build-private-program.mjs,
then import and reuse them in prepare-npm-package.mjs, preserving the existing
validation and metadata shape.
In `@scripts/test-private-program-mutations.mjs`:
- Around line 364-460: Extract the shared lexical and physical boundary
admission primitives from assertAdmittedTree and assertAdmittedRegularFile into
a reusable module, then update test-private-program-browser.mjs and
build-private-program.mjs to use it instead of assertStrictlyContained,
assertNoLinkPath, and pathIsWithin. Preserve the existing symlink,
filesystem-object, and boundary validation behavior at all call sites.
---
Outside diff comments:
In `@crates/labcolors-core/src/program/attachment.rs`:
- Around line 882-951: Сократите дублирование в методах attach и
attach_external, выделив общий приватный помощник attach_with, который выполняет
prepare_attachment_cold, преобразует ошибку подготовки в
AttachmentCreateFailureV2::Contract и вызывает admit_prepared_state с единым
map_err для AttachmentCreateFailureV2::SinkAdmission. Передавайте в помощник
функцию wrap для создания соответствующего результата; сохраните требования
трейтов и текущие типы обёрток каждого публичного метода.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 81d33f07-14eb-470b-801f-d8e564eb65d6
📒 Files selected for processing (46)
.github/workflows/ci-worker.yml.github/workflows/publish-worker.ymlcrates/labcolors-core/Cargo.tomlcrates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.jsoncrates/labcolors-core/contracts/clean-set-srgb8-v1/receipt-v1.sha256crates/labcolors-core/contracts/point-support-reference-surplus-q55-bps-proof-v1.jsoncrates/labcolors-core/src/generic_boundary_tests.rscrates/labcolors-core/src/lib.rscrates/labcolors-core/src/private_fixture.rscrates/labcolors-core/src/program.rscrates/labcolors-core/src/program/attachment.rscrates/labcolors-core/src/program/attachment/handoff.rscrates/labcolors-core/src/program/attachment/support.rscrates/labcolors-core/src/program/attachment/tests.rscrates/labcolors-core/src/program_boundary_tests.rscrates/labcolors-core/src/program_clean_set_tests.rscrates/labcolors-core/src/program_identity.rscrates/labcolors-core/src/program_identity_tests.rscrates/labcolors-core/src/program_relation_tests.rscrates/labcolors-core/src/program_session.rscrates/labcolors-core/src/selection_release.rscrates/labcolors-core/src/selection_release_materialisation_tests.rsfixtures/private-program-browser/index.htmlfixtures/private-program-browser/proof.mjspackages/colors/.gitignorepackages/colors/package.jsonpackages/colors/private-program/consumer.jspackages/colors/test/atomic-write-durability.test.mjspackages/colors/test/private-program-ci-contract.test.mjspackages/colors/test/private-program-consumer.test.mjspackages/colors/test/private-program-mutation-contract.test.mjspackages/colors/test/private-program-publish-contract.test.mjspackages/colors/test/private-program-source-snapshot-contract.test.mjspackages/colors/test/private-program-test-prerequisite.test.mjspackages/colors/test/release-contract.test.mjspackages/colors/test/release-provenance.test.mjsscripts/atomic-write.mjsscripts/build-private-program.mjsscripts/check-private-program-wasm-size-budget.mjsscripts/ensure-private-program-artifact.mjsscripts/inspect-npm-tarball.pyscripts/prepare-npm-package.mjsscripts/test-private-program-browser.mjsscripts/test-private-program-mutations.mjsscripts/verify-package-release.mjsscripts/verify_point_support_surplus.py
…ts and release Both the package test prerequisite and release:verify now produce the private Program artifact through one child-boundary primitive (run-canonical-private-program-build.mjs): spawn, env filtering, and timeout live in a single module, the child environment drops exactly the isCanonicalBuildEnvOverride overrides, required toolchain pins pass through untouched, the strict direct validator is unchanged, and child failure propagates loudly. This closes the release path under the pinned caller worker's ambient CARGO_INCREMENTAL=0, which previously failed the in-process build in verify-package-release.mjs. test_mutation.py: the publish-worker registry test now parses the multi-line run block scalar semantically and proves fail-closed behavior against eight hostile mutants (second npm publish, missing --ignore-scripts, wrong or alternate registry, unquoted or foreign tarball, missing pre-publish sha256 recheck, injected NPM_REGISTRY), while still asserting exactly one publish, the exact quoted tarball, and the adjacent recheck. Latent release blocker surfaced by the required release:verify proof: expectedPackedFiles rejected npm's declared "./index.d.ts" types spelling under the stricter pack-path normaliser; the types field is now normalised exactly like an export target.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/colors/test/private-program-test-prerequisite.test.mjs`:
- Around line 154-165: Усилить тест вокруг runCanonicalPrivateProgramBuild:
проверить не только импорт и наличие экспортов, но и фактическое использование
общего примитива обоими consumer-модулями ensurePrivateProgramArtifact и
verifyPackageRelease. Добавьте наблюдаемую проверку через контролируемую
dependency injection либо отдельный контракт consumer-модулей, чтобы локальная
копия build-логики не проходила тест.
In `@scripts/test_mutation.py`:
- Around line 2110-2130: Усилить validator в _assert_publish_script_fail_closed,
связав SHA-256-проверку с точным путём "$TARBALL_PATH": проверять наличие
команды actual_sha256="$(sha256sum --binary -- "$TARBALL_PATH")", а не
независимых фрагментов. В словаре mutants добавить отдельную мутацию, заменяющую
аргумент этой команды на "$FOREIGN_PATH", и убедиться, что она отклоняется.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 0d2bd57d-6434-459e-be24-a3d353bc4203
📒 Files selected for processing (6)
packages/colors/test/private-program-test-prerequisite.test.mjspackages/colors/test/release-contract.test.mjsscripts/ensure-private-program-artifact.mjsscripts/run-canonical-private-program-build.mjsscripts/test_mutation.pyscripts/verify-package-release.mjs
begin_dispose_v1 returned raw generation tokens from the same small-integer range as PrivateFixtureErrorV1 status codes, so after twelve run/dispose cycles a live token 12 was indistinguishable from InternalInvariant and a consumer could leave the attachment Disposing forever. Live tokens now live in [0x10000000, 0x1fffffff], disjoint from every status code and both sentinels; abort/commit decode the wire token and fail closed with InvalidDisposeToken outside the live range. Remove the never-constructed HandoffPointSinkHostErrorV1::Busy variant and document why Relaxed ordering suffices for the handoff epoch counter.
… budgets - derive the wasm-job deadline ledger and the mutation ms timeout from one WASM_JOB_TIMEOUT_MINUTES budget source instead of duplicated literals (timeout-minutes keeps its match-required comment) - export assertWasm/artifactMetadata from build-private-program.mjs and reuse them in prepare-npm-package.mjs; drop the duplicated local helpers - wrap the runtime WASM toolchain pin read in the typed fail contract and simplify the unreachable optimizer-null branch; share one assertOptimizerConfigurationComplete law between configuredOptimizer and buildPrivateProgram - make the hermetic child environment test deterministic outside CI by spelling out every canonical pin instead of inheriting process.env - guard symlink scenarios with a real symlink-support probe (EPERM on Windows without Developer Mode skips only the symlink scenario), create a fakeBin python3.exe alias instead of asserting a system python3.exe, normalize the inherited PATH key case-insensitively before substitution, and parse GITHUB_OUTPUT on the first '=' with CRLF-tolerant splitting - locate the WASM memory section by parsing section headers instead of scanning for the byte pattern; add a decoy regression test - make the prepack fixture closure-check its relative import graph so an incomplete fixture fails distinctly from the guard regression - document the local Binaryen/rustup pins required by npm test and prepack
The shared-helper refactor removed the local sha256 arrow function while prepareNpmPackage still calls it when building build-metadata.json, which the release gate exercised as ReferenceError: sha256 is not defined. Restore the helper and lock the definition in the prepack source contract test so the removal fails there instead of inside the release verifier.
|
@coderabbitai review |
|
Close two CodeRabbit Major threads (test-strength only, no production defect). F1: the prerequisite test no longer checks only export existence — it now asserts the consumer-module contract for both consumers: each must import and call runCanonicalPrivateProgramBuild from the canonical module and must not embed its own build boundary (spawnSync, hermeticBuildEnvironment, isCanonicalBuildEnvOverride, CHILD_BUILD_TIMEOUT_MS, --require-optimizer). A local copy of the build logic inside a consumer is rejected by the mutant loop, and a scratch regression with a local-copy consumer fails the strengthened test while the real consumers pass 6/6. F2: the publish-worker registry validator binds the exact pre-publish commands instead of independent fragments — the sha256 command must be exactly actual_sha256="$(sha256sum --binary -- "$TARBALL_PATH")" and the digest comparison must be the exact guarded if-line. A new foreign-sha256sum mutant is rejected; a scratch demonstration shows the fragment-only validator lets a foreign-path hash with a spurious "$TARBALL_PATH" mention slip through while the exact-command validator rejects it.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/test_mutation.py (1)
2191-2216: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winЗапретите переназначение
TARBALL_PATHперед публикацией.Текущая проверка принимает мутацию
TARBALL_PATH="/tmp/foreign.tgz"передsha256sum. В этом случае перепроверка иnpm publishиспользуют другой файл. Добавьте проверку запрета присваиваний в publish-шаге и мутацию для этого случая. Проверьте также записиTARBALL_PATHчерезGITHUB_ENVв предыдущих шагах job.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/test_mutation.py` around lines 2191 - 2216, Extend the publish-step validation around publish_index/pre_publish to reject any reassignment of TARBALL_PATH before npm publish, including shell assignments and writes through GITHUB_ENV in earlier job steps. Add a mutation case that changes TARBALL_PATH to a foreign tarball before the sha256sum check, and assert the generated workflow detects and rejects it.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/colors/test/private-program-test-prerequisite.test.mjs`:
- Around line 184-206: Update assertDelegatesToSharedPrimitive in the test to
validate the shared import and runCanonicalPrivateProgramBuild invocation
without depending on quote style, whitespace, or whether an options object is
passed. Use AST inspection or equivalent formatting-tolerant matching, while
preserving the existing rejection of embedded build-boundary symbols.
In `@packages/colors/test/release-provenance.test.mjs`:
- Around line 53-63: Расширьте проверку в assertPrepackFixtureScriptClosure,
чтобы она находила относительные импорты и реэкспорты с одинарными или двойными
кавычками, включая пути ./ и ../, а также динамические вызовы import().
Извлекайте имя .mjs-файла из всех поддерживаемых форм и проверяйте каждый
найденный файл через scriptFiles.includes, сохранив существующее сообщение об
отсутствующей зависимости.
In `@scripts/build-private-program.mjs`:
- Around line 1114-1120: Update the failure handling after toolchain selection
in the surrounding build flow to distinguish requireOptimizer === true from
requireOptimizer === false. Preserve the existing optimized-artifact message for
the canonical path, but use a receipt/build.toolchain-specific message when
requireOptimizer is false and receipt?.build?.toolchain is missing.
---
Outside diff comments:
In `@scripts/test_mutation.py`:
- Around line 2191-2216: Extend the publish-step validation around
publish_index/pre_publish to reject any reassignment of TARBALL_PATH before npm
publish, including shell assignments and writes through GITHUB_ENV in earlier
job steps. Add a mutation case that changes TARBALL_PATH to a foreign tarball
before the sha256sum check, and assert the generated workflow detects and
rejects it.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 824eca31-6444-4103-bf87-babd3e018fe1
📒 Files selected for processing (14)
.github/workflows/ci-worker.ymlcrates/labcolors-core/src/private_fixture.rscrates/labcolors-core/src/program/attachment/handoff.rspackages/colors/README.mdpackages/colors/private-program/consumer.jspackages/colors/test/private-program-ci-contract.test.mjspackages/colors/test/private-program-consumer.test.mjspackages/colors/test/private-program-mutation-contract.test.mjspackages/colors/test/private-program-test-prerequisite.test.mjspackages/colors/test/release-contract.test.mjspackages/colors/test/release-provenance.test.mjsscripts/build-private-program.mjsscripts/prepare-npm-package.mjsscripts/test_mutation.py
|
@coderabbitai resolve |
✅ Action performedComments resolved and changes approved. |
…n publish Close the final verifier class: a mutant that reassigns TARBALL_PATH="/tmp/foreign.tgz" immediately before the exact sha256 recheck command vacuously satisfies every exact-command binding while both the recheck and npm publish operate on the foreign path. The validator now rejects ANY assignment to TARBALL_PATH or TARBALL_SHA256 inside the publish script (bare, export/readonly/local, env-prefixed, or +=) - the identities are bound exactly once by the workflow env block and must never be rebound in the script. Three mutants lock the class: a bare TARBALL_PATH rebind, an export-form rebind, and a TARBALL_SHA256 rebind, each placed before the recheck. RED first: all three slipped through the previous validator; sabotage check: removing the rule lets all three slip again. Full scripts/test_mutation.py: 56/56; the real publish-worker.yml script passes the strengthened validator unchanged.
… write blacklist The isolated verifier proved that no blacklist of shell write mechanisms can close the rebinding class: printf -v TARBALL_PATH, read -r TARBALL_PATH, eval 'TARBALL_PATH=...', indirect printf -v via a name variable, and positional indirection all survive assignment-pattern checks while still rebinding the verified tarball identity before the recheck. The token-bearing publish step now has a canonical golden contract: the validator requires the run block to be byte-for-byte the reviewed canonical form, so every deviation - a rebind by any mechanism, a reorder, an added indirection, even a comment - is rejected, and any legitimate workflow change is an explicit reviewed golden update. Five mutants lock the verifier's exact forms; RED first showed all five slipping through the blacklist, GREEN rejects all seventeen mutants, and the sabotage check (golden removed) lets exactly those five slip again. The real publish-worker.yml script passes the golden unchanged. Full scripts/test_mutation.py: 56/56.
What
Private, declarative walking-skeleton slice behind gate C7c. Adds the private program (Rust core + WASM build), the JS consumer, fixtures, and the full build -> publish -> verify lifecycle driven by
build-private-program/prepare-npm-package, with an exact WASM size budget enforced bycheck-private-program-wasm-size-budget. The public surface stays unchanged until gate C7c is intentionally opened.Why
Establish the end-to-end private publish path (build, bundle, publish, verify against the exact artifact) early, while keeping the public surface and existing release contract intact and reversible.
Invariants
scripts/atomic-write.mjs) with durability tests.verify-package-release, release-contract / release-provenance tests).Verification
Stage A local gates (architecture, appsec, executable) passed after canonical attestation regeneration. Classified local REDs are tracked out-of-band, not reproduced here.
Expected external gates (CI): checks triggered at this exact head must pass. Stage B - the Linux WASM size-budget run and caller re-pin confirmation - is a deliberate fail-closed gate and is NOT claimed or proven locally in this PR.
Rollback
Branch-only change; revert is a single commit revert. No schema or data migration. Reverting restores the previous public surface unchanged.
Summary by CodeRabbit
Новые возможности
Исправления
Тесты