diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml index e8a63a0..fb3452d 100644 --- a/.github/ISSUE_TEMPLATE/bug-report.yml +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -16,7 +16,7 @@ body: attributes: label: Version or commit description: Provide the package version, image tag, or commit SHA. - placeholder: 0.1.0 + placeholder: 0.2.0 validations: required: true diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 683cfb1..e96df39 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -28,11 +28,11 @@ environment. 24, and 26. It also runs dependency review, dependency audit, full-history secret scanning and generates an SPDX JSON source SBOM. Dependency review requires a public repository or the corresponding GitHub security entitlement. -- `alpha-acceptance.yml` verifies the seven synthetic migration goldens and generates one representative Node, - Python, PHP and Go project. It installs each selected toolchain, verifies `monox.lock`, builds and tests the - workspaces, then starts the Node, Python and Laravel APIs and probes their health endpoints. A separate job - exercises the built-in local Cloudapter through doctor, deploy, an explicit health probe, status and - owned-service destroy. This is representative coverage, not the complete catalog matrix. +- `release-acceptance.yml` verifies the seven synthetic migration goldens and generates one representative + Node, Python, PHP and Go project. It installs each selected toolchain, verifies `monox.lock`, builds and + tests the workspaces, then starts the Node, Python and Laravel APIs and probes their health endpoints. A + separate job exercises the built-in local Cloudapter through doctor, deploy, an explicit health probe, + status and owned-service destroy. This is representative coverage, not the complete catalog matrix. - `catalog-matrix.yml` is scheduled weekly and can be started manually. It generates every one of the 24 bundled workspace recipes in isolation, installs the selected toolchain, verifies the lock, runs tests and builds. It then runs the shared acceptance helper, which probes services, checks workers, waits for jobs and @@ -52,10 +52,11 @@ environment. continue to block publication. `create-monox` exists on npm under the `mosharush` maintainer account. Version 0.1.0 was the first release -from this public repository and upgraded the historical 0.0.5 package in place. The public `latest` tag is -currently 0.1.2; the 0.2 source stays on an alpha prerelease until the release gates are complete. Releases -keep the `https://github.com/Mosharush/MonoX` metadata, include the MIT license in the tarball, and use -trusted publishing with registry provenance. +from this public repository and upgraded the historical 0.0.5 package in place. Stable releases publish under +`latest`; prereleases publish under `next`. Verification waits for registry propagation, checks the expected +dist-tag, signed provenance and exact Git commit, then runs a clean-cache consumer. Releases keep the +`https://github.com/Mosharush/MonoX` metadata, include the MIT license in the tarball, and use trusted +publishing without a long-lived npm token. CodeQL uses GitHub default setup with JavaScript and TypeScript analysis. Keep that repository-level setup instead of adding a duplicate advanced workflow. diff --git a/.github/workflows/npm-release-verification.yml b/.github/workflows/npm-release-verification.yml index 27223e8..324b408 100644 --- a/.github/workflows/npm-release-verification.yml +++ b/.github/workflows/npm-release-verification.yml @@ -93,6 +93,7 @@ jobs: PACKAGE_VERSION: ${{ steps.release.outputs.package_version }} RELEASE_TAG: ${{ inputs.release_tag }} SOURCE_SHA: ${{ steps.release.outputs.source_sha }} + VERIFY_DIST_TAG: ${{ github.event_name != 'workflow_dispatch' }} run: | set -euo pipefail @@ -145,6 +146,43 @@ jobs: sleep 10 done + if [[ "${VERIFY_DIST_TAG}" == "true" ]]; then + if [[ "${PACKAGE_VERSION}" == *-* ]]; then + expected_dist_tag="next" + else + expected_dist_tag="latest" + fi + for attempt in {1..18}; do + tag_cache="$(mktemp -d)" + tag_record="$( + NPM_CONFIG_CACHE="${tag_cache}" \ + npx --yes "npm@${NPM_CLI_VERSION}" view \ + create-monox dist-tags \ + --json \ + --workspaces=false 2>/dev/null || true + )" + if DIST_TAG_RECORD="${tag_record}" \ + EXPECTED_DIST_TAG="${expected_dist_tag}" \ + PACKAGE_VERSION="${PACKAGE_VERSION}" \ + node --input-type=module -e " + try { + const raw = JSON.parse(process.env.DIST_TAG_RECORD); + const tags = Array.isArray(raw) ? raw[0] : raw; + process.exit(tags?.[process.env.EXPECTED_DIST_TAG] === process.env.PACKAGE_VERSION ? 0 : 1); + } catch { + process.exit(1); + } + "; then + break + fi + if [[ "${attempt}" -eq 18 ]]; then + echo "npm dist-tag ${expected_dist_tag} does not point to ${PACKAGE_VERSION}." >&2 + exit 1 + fi + sleep 10 + done + fi + package_integrity="$( REGISTRY_RECORD="${registry_record}" node --input-type=module -e \ "const raw = JSON.parse(process.env.REGISTRY_RECORD); const data = Array.isArray(raw) ? raw[0] : raw; process.stdout.write(data?.['dist.integrity'] ?? data?.dist?.integrity ?? '')" diff --git a/.github/workflows/alpha-acceptance.yml b/.github/workflows/release-acceptance.yml similarity index 98% rename from .github/workflows/alpha-acceptance.yml rename to .github/workflows/release-acceptance.yml index 60fcab0..4410f1b 100644 --- a/.github/workflows/alpha-acceptance.yml +++ b/.github/workflows/release-acceptance.yml @@ -1,4 +1,4 @@ -name: 0.2 alpha acceptance +name: 0.2 release acceptance on: push: @@ -11,7 +11,7 @@ permissions: contents: read concurrency: - group: alpha-acceptance-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + group: release-acceptance-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true env: diff --git a/CHANGELOG.md b/CHANGELOG.md index 1aa987f..7624691 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ All notable changes will be documented here. ## Unreleased +## 0.2.0 - 2026-07-26 + +Version 0.2.0 stabilizes deterministic project generation, package-owned deployment contracts and the +source-tested offline planning and rendering surface. Remote infrastructure execution is not promoted to +stable support: PM2, SSH, Coolify and Kubernetes remain guarded behind injected transports, while AWS and +Google Cloud providers remain plan-only. + ### Added - Package-owned deployment contract v2 with strict JSON Schema, generated TypeScript declarations and a @@ -41,8 +48,8 @@ All notable changes will be documented here. `applications[]` list. - Replaced legacy zero-maximum-replica parking with explicit `suspended: true`. - Replaced side deployments with deterministic variants and provider fields with target bindings. -- Bumped source and `create-monox` metadata to `0.2.0-alpha.1`. A prerelease tag and npm publish remain gated - by the complete acceptance suite and security prerequisites. +- Promoted the deterministic generator and offline contracts to `0.2.0`, published through the protected npm + workflow under `latest` only when the exact release tag and source commit match. - Aligned Nuxt 4 with its project-reference TypeScript layout and Angular 22 with the current `@angular/build` builder. - Namespaced generated Python distributions and modules so workspace names such as `fastapi` cannot shadow a @@ -64,7 +71,9 @@ All notable changes will be documented here. ### Known limitations -- AWS and Google Cloud packages are plan-only in this alpha and do not invoke Pulumi Automation API. +- `create-monox@0.2.0` does not install the source-tree `@monox/cli`; generated projects receive deployment + contracts and fail-closed placeholders, while the delivery CLI remains npm-private. +- AWS and Google Cloud packages are plan-only in 0.2.0 and do not invoke Pulumi Automation API. - PM2, SSH, Coolify and Kubernetes adapters have not completed their live acceptance matrices. - Kubernetes add-on chart coordinates and digests remain intentionally unverified and non-executable. - The private production reference has not completed a MonoX 0.2 canary and proven rollback, so it is not yet diff --git a/README.md b/README.md index 82e189d..41944d3 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,10 @@ Every deployable package owns a versioned `package.json.deployment` block. The r project boundaries, workload profiles, environments, targets and add-ons. There is no second application list to keep in sync. -> Status: `0.2.0-alpha.1` is a source prerelease. The protected npm workflow publishes prereleases under the -> `next` dist-tag only after its release gate passes. The stable npm line remains available through `latest`. +> `create-monox` 0.2.0 is the stable generator release and is published through the `latest` dist-tag. Stable +> support covers deterministic project generation and the source-tested offline contracts described below. +> Remote infrastructure execution remains guarded, acceptance-pending or plan-only as marked in the +> [capability status](docs/capability-status.md). [Project site](https://monox.dev) | [Architecture](docs/architecture.md) | [Deployment contract](docs/deployment.md) | [create-monox on npm](https://www.npmjs.com/package/create-monox) @@ -25,10 +27,10 @@ to keep in sync. ## Generate a product -After the alpha is published under `next`: +Create a project from the stable channel: ```bash -npm create monox@next -- my-product \ +npm create monox@latest -- my-product \ --workspace api=node-fastify-api \ --workspace web=react-vite-web \ --workspace jobs=node-worker \ @@ -120,21 +122,25 @@ immutable. Every resolved base workload and variant must match exactly one targe See [Deployment contract](docs/deployment.md) for the complete resolution order and safety rules. -## CLI +## Source-tree delivery CLI + +The delivery CLI below is tested from this repository with `yarn monox`. It is not installed by +`create-monox@0.2.0`; generated projects receive the deployment contracts and fail-closed placeholders only. +`@monox/cli` remains npm-private until its package scope and independent consumer contract are ready. ```text -monox validate -monox config explain --env [--target ] -monox doctor --env [--target ] -monox plan --env --all|--select |--affected -monox render --env --target --all|--select |--affected --output-dir -monox deploy --env --all|--select |--affected -monox apply --plan -monox status --env --target -monox rollback --env --target --revision -monox destroy --env --target --confirm -monox cloud plan|setup|status|destroy --env --target -monox migrate deployment --from monox-v1|legacy-production --input +yarn monox validate +yarn monox config explain --env [--target ] +yarn monox doctor --env [--target ] +yarn monox plan --env --all|--select |--affected +yarn monox render --env --target --all|--select |--affected --output-dir +yarn monox deploy --env --all|--select |--affected +yarn monox apply --plan +yarn monox status --env --target +yarn monox rollback --env --target --revision +yarn monox destroy --env --target --confirm +yarn monox cloud plan|setup|status|destroy --env --target +yarn monox migrate deployment --from monox-v1|legacy-production --input ``` An environment and one workload selector are mandatory for workload state changes. Production state changes @@ -143,7 +149,7 @@ require `CI=true`, a protected environment and an identity reference. Destroy re ## Maintained catalog -The alpha catalog contains 24 workspace recipes: +The stable generator contains 24 bundled workspace recipes: - JavaScript and TypeScript: Node HTTP, Fastify, Express, Nest, Hono, workers, cron, React, Vue, Next, Nuxt, SvelteKit, Angular and TypeScript libraries. @@ -154,8 +160,8 @@ The alpha catalog contains 24 workspace recipes: Java, .NET and Rust remain extension recipes until they have maintained install, test, build and runtime CI. Yarn, pnpm and npm are supported for JavaScript workspaces. -A scheduled 24-recipe matrix installs, tests, builds and starts or probes every built-in workspace. The first -hosted matrix run remains part of the prerelease evidence gate. +A scheduled 24-recipe matrix installs, tests, builds and starts or probes every built-in workspace. Release +candidates rerun that hosted matrix against the exact candidate commit. The 28 add-on recipes cover data, messaging, AI, search, storage, identity, development, observability and Kubernetes platform components. LocalStack and Mailpit are rejected for production. Stateful Kubernetes @@ -171,7 +177,7 @@ methods are versioned through `Cloudapter`: `doctor`, `validate`, `plan`, `rende Local Docker Compose has a built-in executor that runs only allowlisted `docker compose` argument arrays with `shell: false`, bounded readiness checks and explicit owned services. PM2, SSH, Coolify and Kubernetes retain explicitly injected transports, so the CLI does not infer a host, credential or cluster context. AWS and GCP -are plan-only in this alpha; provider executors and live sandbox apply remain release gates. +are plan-only in 0.2.0; provider executors and live sandbox apply are not part of the stable support contract. ## Work on MonoX @@ -195,8 +201,8 @@ docker compose --env-file infra/local/.env -f infra/local/docker-compose.yml --p `yarn check` covers formatting, repository boundaries, deployment resolution, tests, builds and infrastructure validation. MonoX repository CI repeats the gate on Node.js 22, 24 and 26, tests Yarn, npm and pnpm consumers, audits dependencies, scans the full history and creates an SPDX JSON source SBOM. Generated project CI is -limited to immutable install, lock verification, tests and builds. Alpha acceptance also runs a generated -local Docker target through doctor, deploy, an explicit health probe, status and owned-only destroy. +limited to immutable install, lock verification, tests and builds. The 0.2 acceptance workflow also runs a +generated local Docker target through doctor, deploy, an explicit health probe, status and owned-only destroy. ## Clean-room boundary diff --git a/SECURITY.md b/SECURITY.md index ab33807..8504d10 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,7 +2,8 @@ ## Supported versions -MonoX is pre-release software. Security fixes target the latest `0.x` release and the default branch. +Security fixes target the current `0.2.x` release line and the default branch. Earlier `0.x` releases may +receive fixes when a safe backport is practical. ## Report a vulnerability diff --git a/SUPPORT.md b/SUPPORT.md index 42aa8e7..8bb9fd2 100644 --- a/SUPPORT.md +++ b/SUPPORT.md @@ -4,4 +4,5 @@ Use GitHub Issues for reproducible bugs, scoped feature requests, design questio Discussions can become the long-form support channel after the public repository enables it. Security reports follow [SECURITY.md](SECURITY.md). -MonoX is pre-release software. There is no production support SLA. +MonoX 0.2 has a stable generator and offline-contract support boundary. There is no production support SLA, +and remote adapters keep the acceptance status documented in the repository. diff --git a/apps/api/package.json b/apps/api/package.json index 802dbc0..5609709 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -1,6 +1,6 @@ { "name": "@monox/api", - "version": "0.2.0-alpha.1", + "version": "0.2.0", "private": true, "type": "module", "deployment": { diff --git a/apps/api/src/server.mjs b/apps/api/src/server.mjs index 2da3e6e..256bdf0 100644 --- a/apps/api/src/server.mjs +++ b/apps/api/src/server.mjs @@ -13,7 +13,7 @@ const securityHeaders = { export function createApiServer(options = {}) { const environment = normalizeEnvironment(options.environment ?? process.env.MONOX_ENV ?? 'local'); const startedAt = Date.now(); - const runtime = options.runtime ?? createAppRuntime({ name: '@monox/api', version: '0.2.0-alpha.1' }); + const runtime = options.runtime ?? createAppRuntime({ name: '@monox/api', version: '0.2.0' }); const server = createServer((request, response) => { const requestStartedAt = process.hrtime.bigint(); diff --git a/apps/api/test/server.test.mjs b/apps/api/test/server.test.mjs index 650ed31..a662c33 100644 --- a/apps/api/test/server.test.mjs +++ b/apps/api/test/server.test.mjs @@ -19,7 +19,7 @@ test('serves health and synthetic API responses', async () => { assert.equal(health.status, 200); assert.deepEqual(await health.json(), { name: '@monox/api', - version: '0.2.0-alpha.1', + version: '0.2.0', ready: true, live: true, state: 'running', diff --git a/apps/web/deploy/nginx/monox.dev.conf b/apps/web/deploy/nginx/monox.dev.conf index 30ab321..409d259 100644 --- a/apps/web/deploy/nginx/monox.dev.conf +++ b/apps/web/deploy/nginx/monox.dev.conf @@ -66,7 +66,7 @@ server { error_log /home/monox/logs/nginx/error.log; add_header Content-Language $monox_content_language always; - add_header Content-Security-Policy "default-src 'self'; base-uri 'none'; object-src 'none'; frame-ancestors 'none'; form-action 'none'; script-src 'sha256-yobifisrUX5jmFbF2OJOXGbUsGsYDPdPdkH4ehe2Ll0='; style-src 'self'; img-src 'self' data:" always; + add_header Content-Security-Policy "default-src 'self'; base-uri 'none'; object-src 'none'; frame-ancestors 'none'; form-action 'none'; script-src 'sha256-j5+huJAo2bEyExTIsvCL8uNR05Fe+DupuuQrek0PIb4='; style-src 'self'; img-src 'self' data:" always; add_header Cross-Origin-Opener-Policy "same-origin" always; add_header Cross-Origin-Resource-Policy "same-origin" always; add_header Permissions-Policy "camera=(), geolocation=(), microphone=(), payment=(), usb=()" always; diff --git a/apps/web/package.json b/apps/web/package.json index 9c7f345..3411c0e 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -1,6 +1,6 @@ { "name": "@monox/web", - "version": "0.2.0-alpha.1", + "version": "0.2.0", "private": true, "type": "module", "deployment": { diff --git a/apps/web/public/index.he.html b/apps/web/public/index.he.html index 06f484a..6898879 100644 --- a/apps/web/public/index.he.html +++ b/apps/web/public/index.he.html @@ -18,8 +18,8 @@ content="מייצרים workspaces, boundaries, local services, CI, containers ו-delivery contracts בפקודה אחת." /> - - + + @@ -30,7 +30,7 @@ name="twitter:description" content="מייצרים workspaces, boundaries, local services, CI, containers ו-delivery contracts בפקודה אחת." /> - + @@ -49,7 +49,7 @@ MonoX