@ship.zone/ci-spec 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/.smartconfig.json +46 -0
  2. package/changelog.md +190 -0
  3. package/conformance/archive-cases.json +446 -0
  4. package/conformance/ci-actions/compile-invalid/build-arg-secret-collision.yml +31 -0
  5. package/conformance/ci-actions/compile-invalid/candidate-without-needs.yml +36 -0
  6. package/conformance/ci-actions/compile-invalid/needs-wider-triggers.yml +42 -0
  7. package/conformance/ci-actions/compile-invalid/npm-read-registry-not-allowlisted.yml +34 -0
  8. package/conformance/ci-actions/compile-invalid/publish-job-excludes-tag.yml +57 -0
  9. package/conformance/ci-actions/compile-invalid/shared-memory-above-memory.yml +28 -0
  10. package/conformance/ci-actions/compile-invalid/trigger-kind-without-job.yml +30 -0
  11. package/conformance/ci-actions/invalid/alias-affix-invalid.yml +33 -0
  12. package/conformance/ci-actions/invalid/alias.yml +32 -0
  13. package/conformance/ci-actions/invalid/bridge-network.yml +27 -0
  14. package/conformance/ci-actions/invalid/build-darwin-platform.yml +24 -0
  15. package/conformance/ci-actions/invalid/build-with-steps.yml +27 -0
  16. package/conformance/ci-actions/invalid/concurrency-empty-group.yml +28 -0
  17. package/conformance/ci-actions/invalid/concurrency-without-cancel-in-progress.yml +27 -0
  18. package/conformance/ci-actions/invalid/container-job-build-profile.yml +25 -0
  19. package/conformance/ci-actions/invalid/custom-tag.txt +23 -0
  20. package/conformance/ci-actions/invalid/duplicate-key.txt +24 -0
  21. package/conformance/ci-actions/invalid/egress-bare-wildcard.yml +29 -0
  22. package/conformance/ci-actions/invalid/egress-empty-allowlist.yml +28 -0
  23. package/conformance/ci-actions/invalid/egress-ip-literal.yml +29 -0
  24. package/conformance/ci-actions/invalid/egress-single-label-wildcard.yml +29 -0
  25. package/conformance/ci-actions/invalid/job-publish-permission.yml +28 -0
  26. package/conformance/ci-actions/invalid/job-trigger-undeclared-kind.yml +27 -0
  27. package/conformance/ci-actions/invalid/literal-alias-affix.yml +33 -0
  28. package/conformance/ci-actions/invalid/missing-spec.yml +24 -0
  29. package/conformance/ci-actions/invalid/multiple-documents.yml +25 -0
  30. package/conformance/ci-actions/invalid/npm-read-invalid-scope.yml +33 -0
  31. package/conformance/ci-actions/invalid/oci-darwin-platform.yml +25 -0
  32. package/conformance/ci-actions/invalid/permission-without-publication.yml +31 -0
  33. package/conformance/ci-actions/invalid/publish-order-duplicate.yml +50 -0
  34. package/conformance/ci-actions/invalid/publish-order-missing-kind.yml +48 -0
  35. package/conformance/ci-actions/invalid/publish-order-undeclared-kind.yml +45 -0
  36. package/conformance/ci-actions/invalid/publish-without-permission.yml +31 -0
  37. package/conformance/ci-actions/invalid/publish-without-tag-trigger.yml +31 -0
  38. package/conformance/ci-actions/invalid/release-notes-without-assets.yml +46 -0
  39. package/conformance/ci-actions/invalid/reserved-label-prefix.yml +25 -0
  40. package/conformance/ci-actions/invalid/reserved-label.yml +25 -0
  41. package/conformance/ci-actions/invalid/retention-above-maximum.yml +83 -0
  42. package/conformance/ci-actions/invalid/retention-below-minimum.yml +83 -0
  43. package/conformance/ci-actions/invalid/schema-version-field.yml +26 -0
  44. package/conformance/ci-actions/invalid/shared-memory-below-minimum.yml +28 -0
  45. package/conformance/ci-actions/invalid/shell-string.yml +21 -0
  46. package/conformance/ci-actions/invalid/spec-number.yml +25 -0
  47. package/conformance/ci-actions/invalid/spec-prerelease.yml +25 -0
  48. package/conformance/ci-actions/invalid/spec-range.yml +25 -0
  49. package/conformance/ci-actions/invalid/timeout-above-maximum.yml +26 -0
  50. package/conformance/ci-actions/invalid/timeout-below-minimum.yml +26 -0
  51. package/conformance/ci-actions/invalid/unknown-alias-kind.yml +31 -0
  52. package/conformance/ci-actions/invalid/unknown-key.yml +24 -0
  53. package/conformance/ci-actions/invalid/vm-darwin-candidate.yml +38 -0
  54. package/conformance/ci-actions/invalid/vm-darwin-shared-memory.yml +28 -0
  55. package/conformance/ci-actions/invalid/vm-oci-execution.yml +25 -0
  56. package/conformance/ci-actions/invalid/vm-unsupported-platform.yml +25 -0
  57. package/conformance/ci-actions/invalid/vm-without-platform.yml +24 -0
  58. package/conformance/ci-actions/valid/concurrency.yml +83 -0
  59. package/conformance/ci-actions/valid/egress.yml +40 -0
  60. package/conformance/ci-actions/valid/image-build.yml +80 -0
  61. package/conformance/ci-actions/valid/matrix.yml +45 -0
  62. package/conformance/ci-actions/valid/minimal.yml +25 -0
  63. package/conformance/ci-actions/valid/npm-read.yml +60 -0
  64. package/conformance/ci-actions/valid/release-assets.yml +114 -0
  65. package/conformance/ci-actions/valid/release-signing.yml +71 -0
  66. package/conformance/ci-actions/valid/release.yml +109 -0
  67. package/conformance/ci-actions/valid/resources.yml +79 -0
  68. package/conformance/ci-actions/valid/vm.yml +77 -0
  69. package/conformance/compile-cases.json +5885 -0
  70. package/conformance/compile-cases.schema.json +766 -0
  71. package/conformance/digest-cases.json +144 -0
  72. package/conformance/runner-cases.json +1238 -0
  73. package/conformance/runner-jobs/invalid/bridge-network.json +70 -0
  74. package/conformance/runner-jobs/invalid/build-darwin-platform.json +100 -0
  75. package/conformance/runner-jobs/invalid/build-with-steps.json +111 -0
  76. package/conformance/runner-jobs/invalid/build-without-microvm.json +100 -0
  77. package/conformance/runner-jobs/invalid/egress-empty-allowlist.json +71 -0
  78. package/conformance/runner-jobs/invalid/mutable-image.json +70 -0
  79. package/conformance/runner-jobs/invalid/npm-read-reserved-environment.json +82 -0
  80. package/conformance/runner-jobs/invalid/oci-darwin-platform.json +71 -0
  81. package/conformance/runner-jobs/invalid/push-permission-container.json +70 -0
  82. package/conformance/runner-jobs/invalid/shared-memory-below-minimum.json +71 -0
  83. package/conformance/runner-jobs/invalid/timeout-missing.json +69 -0
  84. package/conformance/runner-jobs/invalid/vm-without-microvm.json +82 -0
  85. package/conformance/runner-jobs/valid/candidate-test.json +72 -0
  86. package/conformance/runner-jobs/valid/egress.json +80 -0
  87. package/conformance/runner-jobs/valid/image-build.json +100 -0
  88. package/conformance/runner-jobs/valid/minimal.json +70 -0
  89. package/conformance/runner-jobs/valid/npm-read.json +81 -0
  90. package/conformance/runner-jobs/valid/resources.json +71 -0
  91. package/conformance/runner-jobs/valid/timeout-retention-defaults.json +91 -0
  92. package/conformance/runner-jobs/valid/vm-darwin.json +70 -0
  93. package/conformance/runner-jobs/valid/vm.json +82 -0
  94. package/conformance/runner-messages.json +2035 -0
  95. package/conformance/version-cases.json +125 -0
  96. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  97. package/dist_ts/00_commitinfo_data.js +9 -0
  98. package/dist_ts/constants.d.ts +199 -0
  99. package/dist_ts/constants.js +106 -0
  100. package/dist_ts/index.d.ts +1 -0
  101. package/dist_ts/index.js +2 -0
  102. package/dist_ts/plugins.d.ts +1 -0
  103. package/dist_ts/plugins.js +3 -0
  104. package/examples/ci_actions.yml +64 -0
  105. package/license.md +21 -0
  106. package/package.json +72 -0
  107. package/readme.md +146 -0
  108. package/schemas/ci_actions.schema.json +1664 -0
  109. package/schemas/runner-job.schema.json +1172 -0
  110. package/spec/ci-actions.md +433 -0
  111. package/spec/runner-protocol.md +378 -0
  112. package/spec/runner.openapi.json +2182 -0
  113. package/ts/00_commitinfo_data.ts +8 -0
  114. package/ts/constants.ts +112 -0
  115. package/ts/index.ts +1 -0
  116. package/ts/plugins.ts +1 -0
@@ -0,0 +1,46 @@
1
+ {
2
+ "@git.zone/cli": {
3
+ "schemaVersion": 2,
4
+ "projectType": "npm",
5
+ "module": {
6
+ "githost": "code.foss.global",
7
+ "gitscope": "ship.zone",
8
+ "gitrepo": "ci-spec",
9
+ "description": "The ship.zone CI standard: language-neutral CI workflow and runner protocol specifications.",
10
+ "npmPackagename": "@ship.zone/ci-spec",
11
+ "license": "MIT",
12
+ "projectDomain": "ship.zone",
13
+ "keywords": [
14
+ "ci",
15
+ "continuous-integration",
16
+ "ship.zone",
17
+ "openapi",
18
+ "runner",
19
+ "workflow"
20
+ ]
21
+ },
22
+ "release": {
23
+ "targets": {
24
+ "git": {
25
+ "enabled": true,
26
+ "remote": "origin",
27
+ "pushBranch": true,
28
+ "pushTags": true
29
+ },
30
+ "npm": {
31
+ "enabled": true,
32
+ "registries": [
33
+ "https://verdaccio.lossless.digital",
34
+ "https://registry.npmjs.org"
35
+ ],
36
+ "accessLevel": "public"
37
+ },
38
+ "docker": {
39
+ "enabled": false,
40
+ "engine": "tsdocker",
41
+ "patterns": []
42
+ }
43
+ }
44
+ }
45
+ }
46
+ }
package/changelog.md ADDED
@@ -0,0 +1,190 @@
1
+ # Changelog
2
+
3
+ ## 2026-09-27 - 2.0.0
4
+
5
+ ### Breaking Changes
6
+
7
+ - move the CI standard to the ship.zone brand (package, ci-actions, runner-protocol)
8
+ - The package is published as `@ship.zone/ci-spec`; install it with `pnpm add @ship.zone/ci-spec` and change every import and asset subpath from `@foss.global/ci-spec`. Exported names and subpaths are unchanged. The repository moves to `https://code.foss.global/ship.zone/ci-spec`.
9
+ - Normative identifiers are renamed:
10
+
11
+ | 1.x | 2.0.0 |
12
+ | --- | --- |
13
+ | `FOSS_CI_MATRIX_JSON` | `SHIPZONE_CI_MATRIX_JSON` |
14
+ | `FOSS_CI_INPUTS_JSON` | `SHIPZONE_CI_INPUTS_JSON` |
15
+ | reserved environment names `FOSS_CI_*` | `SHIPZONE_CI_*` |
16
+ | reserved image label prefix `global.foss.ci.` | `zone.ship.ci.` |
17
+ | `https://foss.global/spec/ci/ci_actions.schema.json` | `https://ship.zone/spec/ci/schemas/ci_actions.schema.json` |
18
+ | `https://foss.global/spec/ci/runner-job.schema.json` | `https://ship.zone/spec/ci/schemas/runner-job.schema.json` |
19
+
20
+ - The runner protocol, OpenAPI description, and schemas carry ship.zone titles, and the prose names the coordinator and runner roles instead of a product: the atomic alias write applies to a registry the coordinator operates.
21
+ - 1.x cross-version rules removed. `resources`, `leaseFeatures`, and `maximumTimeoutMs` are plain optional capability fields of 2.0.0, without the per-field rules that a runner sends them only to a coordinator of 1.1.0 or 1.2.0 and later; the general rule stays that a message uses only constructs defined at the lower of the coordinator and runner versions, so later 2.x minor versions add fields the same way. Every coordinator stores and delivers only secret values of at least 8 bytes, so the clauses for coordinators before 1.2.0 are gone. The behavior case `capability-fields-negotiated`, which described a 1.2.0 and 1.1.x session, is removed.
22
+ - Schema identifiers follow the package layout, and the OpenAPI description is `https://ship.zone/spec/ci/spec/runner.openapi.json`, so its `../schemas/runner-job.schema.json` reference resolves to the schema's `$id`. Validators register each schema under its `$id` and need no other key.
23
+ - Under the same-major rule, 1.x implementations do not accept 2.0.0 documents and 2.0.0 implementations do not accept 1.x documents; workflows declare `spec: 2.0.0`, and every conformance fixture, the example, and OpenAPI `info.version` move to 2.0.0, which changes the compiled plan digests of the fixtures.
24
+ - complete the compilation rules (ci-actions, runner-protocol)
25
+ - The YAML subset is exact: a key must resolve to a string under the core schema, so a plain `1`, `true`, `null`, or `~` key is rejected; every explicit tag is rejected, including `!!str` and `!`; a leading byte order mark is allowed and counted by the size limit and the workflow digest; an integral float above the safe-integer range is rejected like an unsafe integer.
26
+ - A job that declares an artifact or cache beyond its resolved permissions fails compilation with `permission_insufficient`; it is never compiled with the declaration dropped.
27
+ - A container or VM job whose candidate image lacks its `runner.platform` fails compilation with `candidate_platform_missing`, like a base-image candidate that lacks a platform of the consuming build.
28
+ - Ref names are UTF-8: a forge rejects other ref names at push, so the rule for non-UTF-8 names is gone.
29
+ - Environment names defined at several levels take the innermost value; a secret target equal to an environment name, two references with one target, and any `SHIPZONE_CI_*` name are conflicts.
30
+
31
+ ### Features
32
+
33
+ - define compilation failure codes, compiled jobs, and expanded nodes (ci-actions, runner-protocol)
34
+ - Every compilation failure carries one of 48 stable codes, grouped in the layers `source`, `yaml`, `version`, `schema`, `workflow`, `policy`, and `run` and evaluated in that order; within the `workflow`, `policy`, and `run` layers the first code in table order wins. The secret and grant codes are ordered `secret_untrusted`, `npm_read_untrusted`, `secret_unknown` (new: a reference to a secret the repository does not hold), `protected_secret_denied`, `secret_too_short`, so an untrusted run learns nothing about the repository's secrets.
35
+ - The version check runs before schema validation, so a workflow written against a later version fails with `spec_incompatible` instead of schema errors.
36
+ - Triggers are evaluated after the workflow layers: an event that does not match creates no run, and every event on a commit whose workflow fails an earlier layer creates a failed run.
37
+ - Compiled Jobs defines every member of a compiled job, including `requirements.limits` derived from the declarations and the deployment, `container` isolation for `oci` unless policy requires `microvm`, and the order of `features` and `labels`, so equal inputs compile to identical plan digests. The Compilation Boundary binds each job's `compiledPlanDigest`; no run-level digest is defined.
38
+ - Expanded DAG names nodes `job`, `job[n]` for matrix expansions in expansion order, `job[platform]` for per-platform build jobs, and `job` for the assembly node, and fixes plan order and `needs` edges. Expansion order varies the first-declared matrix dimension slowest.
39
+ - Tag versions strip one lowercase `v`; valid OCI tags match `[A-Za-z0-9_][A-Za-z0-9._-]{0,127}`; aliases are checked on every tag run.
40
+ - `conformance/compile-cases.json` with `conformance/compile-cases.schema.json` (exported as `compile-cases.json` and `compile-cases.schema.json`) lists the failure codes, 14 trigger pattern vectors, 10 tag version vectors, and 149 compile cases: the expected code of every invalid and compile-invalid workflow fixture, and vectors for the YAML subset, numbers, versions, every workflow and policy rule but the command size and generic policy refusal, trigger matching, matrix expansion and its JSON bytes, manual inputs, tag runs and aliases, job skipping, and the secret code precedence; 13 of them fix compiled nodes, 28 compiled jobs, and their plan digests. The YAML-level fixtures `alias.yml`, `custom-tag.txt`, `duplicate-key.txt`, and `multiple-documents.yml` now break only their YAML rule.
41
+ - The package exports `compilationFailureLayers` and `compilationFailureCodes`, and `ciSpecAssetPaths` gains `compileCases` and `compileCasesSchema`.
42
+ - Adds 11 behavior cases.
43
+
44
+ ## 2026-09-27 - 1.2.0
45
+
46
+ ### Features
47
+
48
+ - refuse secret values shorter than the redaction minimum (ci-actions, runner-protocol)
49
+ - The coordinator refuses to store a secret value, new or as a replacement, that is shorter than 8 UTF-8 bytes, with code `secret_too_short`, and stores nothing. The rule concerns the whole value: a multi-line value is stored whatever the length of its lines. The rule covers every scope a job can reference a secret from.
50
+ - A held value that fails the rule is never delivered: compiling a run in which a non-skipped job references it fails with `secret_too_short`; `secret_untrusted` and `protected_secret_denied` take precedence.
51
+ - Secret Redaction defines the lines of a value (terminators CR LF, LF, and CR) and cross-references the rule. Every stored value is redacted as a whole; lines shorter than 8 bytes of a multi-line value stay unmasked by design. npm grant tokens contain no line terminator.
52
+ - derive the trust class of a run (ci-actions, runner-protocol)
53
+ - Every pull request run is untrusted, whatever its author or head repository. Branch push, tag push, and manual runs are trusted when their actor may push to the repository when the run is created, and untrusted otherwise. The class is fixed at run creation, and neither workflow content nor deployment policy changes it.
54
+ - Trusted pull request runs no longer exist, so the `protected_secret_denied` rule and its behavior case name only branch push, manual, and unprotected tag runs.
55
+ - A job is leased only to a runner whose registration allows its run's trust class: trusted, untrusted, or both. Protected tag runs are trusted. The trust class stays off the wire.
56
+ - let runners advertise the lease features they use and their longest job timeout (runner-protocol)
57
+ - `RunnerCapabilities` accepts the optional `leaseFeatures` (`LeaseFeature`: `image-pull-grants`, `candidate-bindings`, `npm-read-grants`) and `maximumTimeoutMs` (1,000 to 86,400,000). When advertised, a lease uses only listed features and a job's `timeoutMs` is at most the maximum; `candidate-bindings` requires `image-pull-grants`. Runners send both only when the lower of the coordinator and runner versions is 1.2.0 or later.
58
+ - A grant applies to an image reference whose registry (the text before the first `/`) and repository (the text up to `@`) equal the grant's exactly; a reference without a registry has no grant, and the runner presents a pull grant only for an image it applies to.
59
+ - The package exports `leaseFeatureIdentifiers`.
60
+ - Adds 15 behavior cases and 7 wire-message cases.
61
+
62
+ ## 2026-09-27 - 1.1.1
63
+
64
+ ### Fixes
65
+
66
+ - define run concurrency (ci-actions, runner-protocol)
67
+ - A run whose workflow declares `concurrency` has a concurrency key: tenant, repository, trust class, whether it is a protected tag run, its ref (the branch or tag ref, the pull request, or the ref a manual run executes), and the literal `group`. Only runs with the same key affect each other, so untrusted runs never delay or cancel trusted runs and only protected tag runs affect protected tag runs.
68
+ - At most one run per key is active; runs with one key start in creation order, and the coordinator enqueues no job of a waiting run. With `cancelInProgress: true` a new run cancels older waiting runs and the older active run: unenqueued and queued jobs become `canceled` without a lease and running attempts receive a cancellation directive with reason `superseded`. A run that has begun qualification or publication is never canceled by concurrency.
69
+ - `concurrency` is not part of any compiled job or plan digest; a run without it, or whose compilation failed, never waits or cancels.
70
+ - define the job timeout default and deadline (ci-actions, runner-protocol)
71
+ - A job without `timeoutMs` compiles to 3,600,000 (one hour); every compiled job, matrix expansion, and per-platform build job carries the value explicitly.
72
+ - The attempt timeout is the coordinator's acceptance commit time plus `timeoutMs`; the runner measures its deadline from receiving the acceptance response. The deadline covers source extraction, cache restoration, and the steps, or the build, push, and image record; artifact upload, cache publication, and completion follow it.
73
+ - At the deadline the runner terminates as for a cancellation, archives `always` and `failure` artifacts, publishes no cache, and completes `timed_out`. Grant expiry is bounded by the attempt timeout plus the cancellation grace.
74
+ - define artifact and cache retention (ci-actions, runner-protocol)
75
+ - `retentionDays` defaults to 30 for artifacts and 7 for caches and compiles unchanged. An item expires `retentionDays` days after its `TransferRecord` `createdAt`; from then on it is never served, restored, qualified, or published, and its content is deleted within 7 days.
76
+ - Restoring a cache does not extend its expiry, and an expired current cache is restored as absent. Qualification fails on an expired referenced artifact, and a publication resume that needs one fails, so retention bounds how long publications can be resumed; release assets and npm packages already published are unaffected.
77
+ - A deployment maximum for timeout or retention applies to the declared or default value and fails compilation rather than shortening it.
78
+ - Adds 20 behavior cases, 1 valid and 6 schema-invalid workflow fixtures, and 1 valid and 1 invalid runner-job fixture; a test keeps the timeout and retention bounds of workflows and compiled jobs identical.
79
+
80
+
81
+ ### Maintenance
82
+
83
+ - update the release tooling to `@git.zone/tstest` 6.3.2 and `@git.zone/tsrun` 3.0.1 (tooling)
84
+
85
+ ## 2026-09-26 - 1.1.0
86
+
87
+ ### Features
88
+
89
+ - add per-job shared memory, runner resource maxima, and resource-aware lease matching (runner-protocol, ci-actions)
90
+ - Workflow and compiled job `resources` accept the optional `sharedMemoryBytes`, the size of `/dev/shm` inside the sandbox; a value above the job's `memoryBytes` fails compilation.
91
+ - `RunnerCapabilities` accepts the optional `resources` object (`ResourceLimits`: `maximumMemoryBytes`, `maximumCpus`, `maximumPids`, `maximumSharedMemoryBytes`); when advertised, a job is leased only when every declared resource fits.
92
+ - extend CI publication with alias affixes, a declared publication order, and release notes (ci-actions)
93
+ - A `version` image alias accepts an optional `prefix` and `suffix`, so tags such as `v1.2.3` or `base_1.2.3-alpine` are expressible; an expansion that is not a valid OCI tag of at most 128 characters, or two aliases of one destination expanding to the same tag, fails compilation.
94
+ - The optional `publish.order` lists exactly the declared publication kinds; without it the order stays `images`, `npm`, `releaseAssets`.
95
+ - The optional `publish.releaseNotes` names an artifact holding one UTF-8 file of at most 1 MiB that becomes the release body; it requires `releaseAssets`.
96
+ - Adds 14 behavior cases, 2 wire-message cases, workflow fixtures (2 valid, 7 schema-invalid, 1 compile-invalid), and runner-job fixtures (1 valid, 1 invalid); a test enforces that every document using a construct added in 1.1.0 declares `spec: 1.1.0` or later.
97
+ - add the `vm` execution profile for jobs that need root, a container engine, or kernel facilities (runner-protocol, ci-actions)
98
+ - A `vm` job has the container job shape with `execution.profile: vm`, declares `runner.platform` (a `linux` platform or `darwin/arm64`), and compiles to `microvm` isolation and `requirements.platform`.
99
+ - Each attempt boots one guest; steps run in order as guest root in that guest, and every process a step started is terminated before the next step. A `linux` guest runs the job image's root filesystem on a runner-provided kernel with namespaces, cgroups, loop devices, nftables, and tun; the job image brings its own container engine. No host device is visible and nested virtualization is not guaranteed.
100
+ - Nested namespaces and containers inside the guest are part of the sandbox; every connection leaving the guest passes network enforcement.
101
+ - A runner advertising `vm` includes `microvm` and may also advertise `oci`, never `oci-image`. A `vm` job is leased only to a runner advertising `vm`, `microvm`, and its platform; `darwin/arm64` runners run on Apple silicon and boot a digest-pinned bootable VM image, and `darwin/arm64` jobs declare no `sharedMemoryBytes`.
102
+ - add job trigger filters and protected secrets for tag-only release jobs (ci-actions, runner-protocol)
103
+ - The optional job `triggers` lists the trigger kinds whose runs include the job; other runs skip it and its expansions during compilation. A job may admit only kinds that every job it needs admits, jobs referenced by `publish` admit `tag`, and every declared trigger kind is admitted by some job.
104
+ - A secret a repository marks protected reaches only jobs of protected tag runs, the runs that may publish; compiling any other trusted run in which a non-skipped job references it fails with `protected_secret_denied`, and the conditions are re-checked before every lease.
105
+ - Runners redact every secret value and npm grant token from job logs and reject artifacts and caches that contain one.
106
+ - add attempt-scoped npm read grants for private scopes (ci-actions, runner-protocol)
107
+ - The optional job `npmRead` (`registry`, `scopes`) is part of the compiled job and the plan digest; `JobLease.npmGrants` (`NpmGrant`) carries one read-only token per entry outside the digest, revoked with the attempt.
108
+ - `oci` and `vm` steps receive a read-only npm configuration file outside the workspace through the reserved `NPM_CONFIG_USERCONFIG`, in `vm` on a read-only device or file system the host enforces because steps run as guest root; `oci-image` builds receive it as the reserved BuildKit secret `npmrc`.
109
+ - The runner places a token nowhere else; a copy that job or Dockerfile content makes is outside what a runner can prevent and is bounded by the grant's scopes and its revocation with the attempt.
110
+ - Untrusted runs, including every pull request, fail compilation with `npm_read_untrusted`; each registry must be allowlisted for egress.
111
+ - Exports `executionProfileIdentifiers.virtualMachine`, and adds 20 behavior cases, 8 wire-message cases, workflow fixtures (3 valid, 7 schema-invalid, 4 compile-invalid), and runner-job fixtures (3 valid, 2 invalid).
112
+
113
+ ### Fixes
114
+
115
+ - make loopback traffic inside an attempt explicit and give every attempt its own network namespaces (runner-protocol)
116
+ - Every attempt has network namespaces shared with no other attempt and never with the host; loopback traffic inside them is always permitted, including under `none`, and is not governed by the network mode, so fixed test ports never collide across attempts. `none` now reads "no traffic leaves the sandbox", and the egress rules apply to connections leaving the sandbox.
117
+ - state that the native-platform rule restricts only where a job executes; cross-compiling and running an emulator as an ordinary job process are job content (runner-protocol)
118
+ - define release-asset publication (ci-actions)
119
+ - A release-asset artifact holds regular files at its root; each becomes one asset named by its file name, and nested paths, links, or duplicate asset names fail qualification.
120
+ - The coordinator creates the tag release when absent as a published release (an existing draft is a conflict), marks it as a prerelease exactly when the tag version has a prerelease component, treats an identical existing asset as published and a differing one as a conflict, and succeeds only after downloading every asset back and matching its size and SHA-256. Publications never delete releases or assets.
121
+ - define how job `resources` compile and are enforced (ci-actions, runner-protocol)
122
+ - `workspaceBytes` and `workspaceEntries` compile into `requirements.limits.maximumWorkspaceBytes` and `maximumWorkspaceEntries`; the other values compile unchanged and are ceilings for the whole attempt.
123
+ - state that a microVM guest is created without any state of another attempt rather than empty, which also covers a `vm` guest booted from its job image (runner-protocol)
124
+ - define the protected tag run once and use it for publication and protected secrets; the publication conditions are unchanged (ci-actions)
125
+ - state that cache keys are literal and not matrix-scoped: every job declaring a key, including every expansion of one matrix job, shares that cache in the run's cache namespace (ci-actions)
126
+ - state that untrusted runs receive no secret value, whether or not the secret is marked protected (ci-actions)
127
+ - 1.0.0 said that untrusted pull requests receive no protected secrets before the protected mark existed. Compiling an untrusted run in which a non-skipped job references a secret now fails with the stable code `secret_untrusted`; trusted runs receive unmarked secrets. A 1.0.0 workflow with a `pullRequest` trigger whose jobs reference secrets restricts those jobs with `triggers` (which needs `spec: 1.1.0`) or drops the trigger. Adds 1 behavior case.
128
+ - give protected tag runs a cache namespace of their own (ci-actions, runner-protocol)
129
+ - Jobs of protected tag runs restore only caches that protected tag runs of the same repository published, and their caches are visible to no other run; trust class stays part of every namespace. This keeps caches written by other trusted runs out of jobs that receive protected secrets, and closes the same exposure for publication, where a 1.0.0 tag run could restore a cache any trusted run of the repository had written. Adds 1 behavior case.
130
+ - restrict `oci` and `oci-image` jobs to `linux` platforms (ci-actions, runner-protocol)
131
+ - Both profiles are defined by Linux sandbox and BuildKit facilities, and 1.0.0 defined no other execution for them; `darwin/arm64` is defined only for `vm`. The schemas now reject another platform in an `oci` job's `runner.platform`, in `build.platforms`, and in the `requirements.platform` of a compiled `oci` or `oci-image` job, through the new shared `linuxPlatform` definition, and an `oci` job without a platform is leased only to a runner that advertises a `linux` platform. Adds 1 behavior case, 2 schema-invalid workflows, and 2 invalid runner jobs.
132
+ - state what the runner guarantees for build secrets: it never writes them into a layer, history, configuration, label, or exported cache, while a Dockerfile instruction that copies a mounted secret into the image filesystem is job content the runner cannot prevent (runner-protocol)
133
+
134
+ ### Maintenance
135
+
136
+ - release tooling currency: `pnpm@12.5.1`, `@git.zone/tstest` `^6.3.0` and `@types/node` 26.6.2; tsbuild 5.0.0 and tsrun 3.0.0 are already current (tooling)
137
+
138
+ ## 2026-09-25 - 1.0.0
139
+
140
+ ### Breaking Changes
141
+
142
+ - version the specification as the @foss.global/ci-spec package and add image builds, egress networking, and CI publication (runner-protocol, ci-actions)
143
+ - The package version is the only specification version. `ci_actions.yml` references it once as the required top-level `spec` (exact `MAJOR.MINOR.PATCH`); the `schemaVersion` field is removed.
144
+ - A coordinator or runner implementing version `I` accepts a declared `spec` when it has the same major version and is not newer than `I`; `conformance/version-cases.json` fixes the outcomes.
145
+ - The `2.0-draft.N` protocol identifier and the `foss-ci-runner/…` protocol string are removed: the compiled job `specVersion` becomes `spec` and carries the workflow's `spec`; discovery, registration, and session messages replace `protocol` with `spec`; a runner of a different major version is rejected with HTTP 409 `spec_incompatible`; OpenAPI `info.version` is the specification version.
146
+ - Version suffixes are removed from identifiers: execution profiles `oci.v1` and `oci-image.v1` become `oci` and `oci-image`, features `artifacts.v1` and `caches.v1` become `artifacts` and `caches`, the base path `/api/runner/v2` becomes `/api/runner`, and schema `$id`s drop `.v1`/`.v2`.
147
+ - The TypeScript exports `ciActionsSchemaVersion`, `runnerProtocolVersion`, and `runnerProtocolIdentifier` are removed; `ciSpecVersion` exposes the package version.
148
+ - The compiled runner job is a closed `oneOf` over execution profiles keyed by `requirements.executionProfile`: `oci` jobs carry `execution` and `steps`, `oci-image` jobs carry `build` and no steps.
149
+ - `requirements.isolation` (`container` or `microvm`) is required in every compiled job.
150
+ - The compiled job network moves from the `execution.network` string to a required top-level `network` object; the workflow job `network` becomes the same object shape with a `ports` default of `[443]`.
151
+ - The unrestricted `bridge` network mode is removed from workflows, compiled jobs, and runner capabilities; `egress` with a non-empty host allowlist replaces it and `none` remains the default.
152
+ - Compiled job `permissions.packages` is replaced by the required `permissions.images` (`none` or `push`).
153
+ - Workflow `permissions.packages` is replaced by the required `images` (`none`, `candidate`, `publish`), `npm`, and `releaseAssets` rights; job-level permissions are a separate object limited to `images: none|candidate`.
154
+ - Workflow and compiled `execution.image` accept either a digest-pinned string or a `{ candidate }` reference.
155
+ - `RunnerCapabilities` requires `isolation` and native `platforms`; a runner advertising `oci-image` must advertise only that profile and must include `microvm`.
156
+ - `JobLease` requires `grants` and `bindings` arrays.
157
+
158
+ ### Features
159
+
160
+ - add the `oci-image` build profile, candidates, and coordinator publication (runner-protocol, ci-actions)
161
+ - Defines microVM isolation guarantees, native-only platform matching, and dedicated builder runners.
162
+ - Adds attempt-scoped pull and push image grants and candidate bindings outside the compiled plan digest, and the fenced idempotent `PUT .../attempts/{attemptId}/image` record endpoint.
163
+ - Defines build jobs expanded per platform, deterministic RFC 8785 candidate index assembly, trust-scoped candidate namespaces, and untrusted candidate retention.
164
+ - Defines egress enforcement: runner-owned DNS, address pinning, SNI and Host checks, and blocking of non-global addresses.
165
+ - Adds the workflow `publish` block for image promotion, npm, and release assets with protected-tag qualification, recorded alias predecessors, idempotent publication, and resume by authorized maintainers.
166
+ - Exports `ciSpecVersion`, `executionProfileIdentifiers`, and `runnerFeatureIdentifiers`, publishes `version-cases.json`, and adds workflow, compile-level, runner-job, wire-message, digest, version, and behavior conformance fixtures.
167
+
168
+ ### Maintenance
169
+
170
+ - release tooling currency: `pnpm@12.5.0`, `@git.zone/tsbuild` 5.0.0, `@git.zone/tsrun` 3.0.0, `@git.zone/tstest` 6.2.1, `@types/node` 26.6.1; `test:types` type-checks the tests with library checks instead of `--skiplibcheck` (tooling)
171
+ - keep `readme.hints.md` out of the published package (packaging)
172
+ - npm includes every root `readme.*` file regardless of `files`, so the hints now live in the untracked `.nogit/` folder.
173
+
174
+ ## 2026-07-31 - 0.2.0
175
+
176
+ ### Features
177
+
178
+ - publish runner protocol 2.0-draft.2 archive conformance (runner-protocol)
179
+ - Updates runner protocol identifiers, OpenAPI metadata, runner job schema, and conformance fixtures to 2.0-draft.2.
180
+ - Adds exported tar.gz archive conformance cases covering valid archives, unsafe paths and links, and archive limit failures.
181
+ - Defines the 134,217,728-byte archive path metadata ceiling and exposes it in TypeScript metadata.
182
+
183
+ ## 2026-07-30 - 0.1.0
184
+
185
+ ### Features
186
+
187
+ - add draft CI runner and workflow specifications (spec)
188
+ - Define draft runner v2 protocol, OpenAPI assets, and compiled runner job schema.
189
+ - Add ci_actions.yml schema, protocol documentation, examples, and TypeScript asset metadata exports.
190
+ - Add conformance fixtures and tests for schemas, runner messages, digest canonicalization, and workflow validation.