Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"prepare": "lefthook install",
"release": "pnpm build && changeset publish",
"test": "turbo test",
"test:release-gates": "node --experimental-strip-types scripts/verification-command.mts --id release-gate-tests",
"test:coverage:core": "pnpm --filter @croco/problems-core --filter @croco/telemetry-api --filter @croco/tenant-core --filter @croco/dataloader-core --filter @croco/ratelimit-core --filter @croco/llm-core --filter @croco/storage-core --filter @croco/architecture-policy build && node --experimental-strip-types scripts/verification-command.mts --id core-coverage",
"test:coverage:core:warning": "node --experimental-strip-types scripts/verification-command.mts --id core-coverage-warning",
"typecheck": "turbo typecheck",
Expand Down
1 change: 1 addition & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions pnpm-workspace.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ overrides:
"@hono/node-server": 1.19.10
"@opentelemetry/auto-instrumentations-node": 0.78.0
"@opentelemetry/exporter-prometheus": 0.220.0
"@opentelemetry/propagator-jaeger": 2.9.0
"@opentelemetry/sdk-node": 0.220.0
"@grpc/grpc-js": 1.14.4
"@isaacs/brace-expansion": 5.0.1
Expand Down Expand Up @@ -62,3 +63,7 @@ allowBuilds:
protobufjs: true
sharp: false
workerd: true

auditConfig:
ignoreGhsas:
- GHSA-f88m-g3jw-g9cj
160 changes: 160 additions & 0 deletions scripts/release-gate-maintenance.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
export const RELEASE_GATE_TEST_PATHS = [
"scripts/tests/alpha-release-smoke.spec.ts",
"scripts/tests/api-docs-trigger-check.spec.ts",
"scripts/tests/architecture-policy-check.spec.ts",
"scripts/tests/bench-threshold-check.spec.ts",
"scripts/tests/benchmark-workflow.spec.ts",
"scripts/tests/changeset-required-check.spec.ts",
"scripts/tests/ci-executable-policy.spec.ts",
"scripts/tests/ci-workflow.spec.ts",
"scripts/tests/core-coverage-warning-check.spec.ts",
"scripts/tests/create-croco-app-generated-smoke.spec.ts",
"scripts/tests/dependency-audit-policy.spec.ts",
"scripts/tests/doc-examples-check.spec.ts",
"scripts/tests/first-success-verify.spec.ts",
"scripts/tests/generated-secret-placeholder-policy.spec.ts",
"scripts/tests/normalize-packages.spec.ts",
"scripts/tests/package-bin-smoke.spec.ts",
"scripts/tests/package-docs-check.spec.ts",
"scripts/tests/package-entrypoint-smoke.spec.ts",
"scripts/tests/package-manifest-contracts.spec.ts",
"scripts/tests/package-quality-report.spec.ts",
"scripts/tests/problem-registry.spec.ts",
"scripts/tests/production-ready-check.spec.ts",
"scripts/tests/provenance-config-check.spec.ts",
"scripts/tests/provider-certification-check.spec.ts",
"scripts/tests/public-api-surface.spec.ts",
"scripts/tests/release-docs-check.spec.ts",
"scripts/tests/release-metadata-check.spec.ts",
"scripts/tests/release-spine-evidence.spec.ts",
"scripts/tests/release-workflow.spec.ts",
"scripts/tests/security-allowlist-metadata-check.spec.ts",
"scripts/tests/spine-promotion-check.spec.ts",
"scripts/tests/static-misuse-check.spec.ts",
"scripts/tests/strict-contract-typecheck.spec.ts",
"scripts/tests/tracked-file-mutation-guard.spec.ts",
"scripts/tests/verification-change-classifier.spec.ts",
"scripts/tests/verification-command.spec.ts",
"scripts/tests/verification-manifest.spec.ts",
"scripts/tests/verification-policy.spec.ts",
"scripts/tests/verify-circular-allowlist.spec.ts",
] as const;

export const RELEASE_GATE_ENTRYPOINT_PATHS = [
"scripts/alpha-release-smoke.mts",
"scripts/api-docs-trigger-check.mts",
"scripts/architecture-policy-check.mts",
"scripts/bench-threshold-check.mts",
"scripts/changeset-required-check.mts",
"scripts/ci-executable-policy.mts",
"scripts/core-coverage-warning-check.mts",
"scripts/create-croco-app-generated-smoke.mts",
"scripts/dependency-audit-policy.mts",
"scripts/doc-examples-check.mts",
"scripts/first-success-verify.mts",
"scripts/generated-secret-placeholder-policy.mts",
"scripts/normalize-packages.mjs",
"scripts/package-bin-smoke.mts",
"scripts/package-docs-check.mts",
"scripts/package-entrypoint-smoke.mts",
"scripts/package-quality-report.mts",
"scripts/problem-registry.mts",
"scripts/production-ready-check.mts",
"scripts/provenance-config-check.mts",
"scripts/provider-certification-check.mts",
"scripts/public-api-surface.mts",
"scripts/quick-start-lambda-smoke.mts",
"scripts/release-docs-check.mts",
"scripts/release-metadata-check.mts",
"scripts/security-allowlist-metadata-check.mts",
"scripts/spine-promotion-check.mts",
"scripts/static-misuse-check.mts",
"scripts/strict-contract-typecheck.mts",
"scripts/tracked-file-mutation-guard.mts",
"scripts/verification-policy.mts",
"scripts/verify-circular-allowlist.mts",
] as const;

export const RELEASE_GATE_SUPPORT_PATHS = [
"scripts/certification-policy.mts",
"scripts/create-croco-app-generated-smoke-journey-report.mts",
"scripts/create-croco-app-generated-smoke-matrix.mts",
"scripts/create-croco-app-generated-smoke-report.mts",
"scripts/create-croco-app-generated-smoke-support.mts",
"scripts/first-success-generated-contract.mts",
"scripts/internal-croco-compatibility-policy.mjs",
"scripts/package-manifest-contracts.mjs",
"scripts/peer-dependency-range-policy.mjs",
"scripts/release-gate-maintenance.mts",
"scripts/release-spine-evidence.mts",
"scripts/verification-change-classifier.mts",
"scripts/verification-command.mts",
"scripts/verification-dispatcher.mts",
"scripts/verification-manifest.mts",
"scripts/verification-problem.mts",
"scripts/workflow-verification-contract.mts",
] as const;

export const RELEASE_GATE_IMPLEMENTATION_PATHS = [
...RELEASE_GATE_ENTRYPOINT_PATHS,
...RELEASE_GATE_SUPPORT_PATHS,
] as const;

export const RELEASE_GATE_WORKFLOW_PATHS = [
".github/workflows/benchmark.yml",
".github/workflows/ci.yml",
".github/workflows/release.yml",
] as const;

export const RELEASE_GATE_POLICY_INPUT_PATHS = [
".changeset/config.json",
".github/renovate.json",
".gitignore",
".gitleaks.toml",
".gitleaksignore",
".madge-circular-allowlist.txt",
".npmrc",
".nvmrc",
".oxfmtignore",
".oxfmtrc.json",
".oxlintrc.json",
".prettierignore",
"RELEASING.md",
"benchmarks/baseline.json",
"benchmarks/thresholds.json",
"ci-reports/bundle-size/baseline.json",
"ci-reports/coverage/core-baseline.txt",
"croco.arch.json",
"docs/doc-examples-baseline.json",
"docs/package-catalog.json",
"docs/package-docs-baseline.json",
"docs/problem-code-registry.json",
"docs/release/croco-1.0-spine.md",
"docs/release/silent-success-audit.json",
"package.json",
"pnpm-lock.yaml",
"pnpm-workspace.yaml",
"public-api-surface.snapshot.json",
"scripts/internal-peer-dependency-range-exceptions.json",
"scripts/security-allowlist-metadata.json",
"scripts/static-misuse-empty-catch-allowlist.json",
"scripts/static-misuse-raw-error-allowlist.json",
"tsconfig.json",
"tsconfig/contract-strict.baseline.json",
"turbo.json",
"vitest.config.bench.ts",
"vitest.config.ts",
] as const;

export const RELEASE_GATE_MAINTENANCE_PATHS = [
...RELEASE_GATE_WORKFLOW_PATHS,
...RELEASE_GATE_POLICY_INPUT_PATHS,
...RELEASE_GATE_IMPLEMENTATION_PATHS,
...RELEASE_GATE_TEST_PATHS,
] as const;

const RELEASE_GATE_MAINTENANCE_PATH_SET = new Set<string>(RELEASE_GATE_MAINTENANCE_PATHS);

export function isReleaseGateMaintenancePath(path: string): boolean {
return RELEASE_GATE_MAINTENANCE_PATH_SET.has(path);
}
9 changes: 8 additions & 1 deletion scripts/security-allowlist-metadata.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
{
"schemaVersion": 1,
"audit": {
"ignoreGhsas": []
"ignoreGhsas": [
{
"id": "GHSA-f88m-g3jw-g9cj",
"owner": "kang-heewon",
"reason": "Next.js 15 and 16 constrain their optional sharp dependency to the vulnerable 0.34 line; retain the generated-app compatibility path while upstream adopts sharp 0.35.",
"reviewBy": "2026-08-05"
}
]
},
"secretScan": {
"gitleaks": {
Expand Down
1 change: 1 addition & 0 deletions scripts/tests/ci-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ describe("CI verification profile contract", () => {
'if [ "${{ github.event_name }}" = "pull_request" ]; then\n args+=(--allow-pending-release-metadata --base "${{ steps.verification.outputs.base }}" --head HEAD)',
);
expect(WORKFLOW).toContain('--base "${{ steps.verification.outputs.base }}" --head HEAD');
expect(WORKFLOW).not.toContain("test:release-gates");
});

it("keeps advisory scans and ecosystem smoke outside blocking profiles", () => {
Expand Down
12 changes: 9 additions & 3 deletions scripts/tests/first-success-verify.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { dirname, join, resolve } from "node:path";
import { afterEach, beforeAll, describe, expect, it } from "vitest";
import {
GENERATED_NODE_ENGINE_RANGE,
GENERATED_NODE_VERSION,
} from "../../packages/create-croco-app/src/node-runtime.js";
import { validateGeneratedSaasDocsContract } from "../first-success-generated-contract.mts";

const scriptPath = resolve(__dirname, "../first-success-verify.mts");
Expand Down Expand Up @@ -83,7 +87,7 @@ describe("first-success-verify.mts", () => {

const result = runScript(root);

expect(result.status).toBe(0);
expect(result.status, result.stderr || result.stdout).toBe(0);
expect(result.stdout).toContain("first-success contract verification PASSED");
});

Expand All @@ -95,7 +99,7 @@ describe("first-success-verify.mts", () => {

const result = runScript(root);

expect(result.status).toBe(0);
expect(result.status, result.stderr || result.stdout).toBe(0);
});

it("rejects a quick-start smoke dispatcher with the wrong command ID", () => {
Expand Down Expand Up @@ -179,7 +183,7 @@ describe("first-success-verify.mts", () => {

const result = runScript(root);

expect(result.status).toBe(0);
expect(result.status, result.stderr || result.stdout).toBe(0);
expect(result.stdout).toContain("first-success contract verification PASSED");
});

Expand Down Expand Up @@ -485,6 +489,8 @@ function createFixture(options: FixtureOptions = {}): string {
"pnpm install",
"pnpm dev",
"pnpm quick-start-lambda:smoke",
`Node.js ${GENERATED_NODE_ENGINE_RANGE}`,
`nvm install ${GENERATED_NODE_VERSION}`,
"x-api-key: test-key",
"401",
"api_user_create",
Expand Down
4 changes: 2 additions & 2 deletions scripts/tests/package-entrypoint-smoke.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ describe("package-entrypoint-smoke.mts", () => {
expect(result.stdout).toContain(
"esm decorator metadata and implicit DI ok @croco/metering-core",
);
});
}, 30_000);

it("fails when the packed auth service loses concrete constructor metadata", () => {
const root = createTempRoot();
Expand Down Expand Up @@ -293,7 +293,7 @@ describe("package-entrypoint-smoke.mts", () => {
expect(`${result.stdout}\n${result.stderr}`).toContain(
"Container.get(MeterRegistry) expected default cacheTtlMs=60000",
);
});
}, 30_000);

it("matches packed tarballs by manifest name when package names share a prefix", () => {
const root = createTempRoot();
Expand Down
1 change: 1 addition & 0 deletions scripts/tests/release-workflow.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe("Release verification profile contract", () => {
);
expect(workflow).toContain('pnpm verify:publish -- "${args[@]}"');
expect(workflow.match(/verify:publish/g)).toHaveLength(1);
expect(workflow).not.toContain("test:release-gates");
expect(workflow).not.toContain("--allow-pending-release-metadata");
});

Expand Down
35 changes: 29 additions & 6 deletions scripts/tests/verification-change-classifier.spec.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { describe, expect, it } from "vitest";

import { classifyVerificationChanges } from "../verification-change-classifier.mts";
import { verificationImplementationPaths } from "../verification-manifest.mts";
import {
createVerificationManifest,
verificationImplementationPaths,
} from "../verification-manifest.mts";
import { RELEASE_GATE_MAINTENANCE_PATHS } from "../release-gate-maintenance.mts";
import { formatVerificationProblem, VerificationProblem } from "../verification-problem.mts";

describe("verification change classifier", () => {
Expand All @@ -17,11 +21,11 @@ describe("verification change classifier", () => {
[[".github/workflows/ci.yml"], "publish"],
[[".changeset/new.md"], "repo"],
[["packages/retry-core/package.json"], "publish"],
[["turbo.json"], "spine"],
[["vitest.config.ts"], "spine"],
[["tsconfig.json"], "spine"],
[[".nvmrc"], "spine"],
[[".gitignore"], "spine"],
[["turbo.json"], "publish"],
[["vitest.config.ts"], "publish"],
[["tsconfig.json"], "publish"],
[[".nvmrc"], "publish"],
[[".gitignore"], "publish"],
] as const)("routes pull request files %j to %s", (files, profile) => {
expect(classifyVerificationChanges("pull_request", files, "ci")).toMatchObject({
profile,
Expand Down Expand Up @@ -81,6 +85,25 @@ describe("verification change classifier", () => {
},
);

it.each(RELEASE_GATE_MAINTENANCE_PATHS)(
"routes authoritative release-gate maintenance %s through publish verification",
(path) => {
for (const event of ["pull_request", "push"] as const) {
const classification = classifyVerificationChanges(event, [path]);
expect(classification).toMatchObject({
profile: "publish",
shouldRunVerification: true,
});
const releaseGate = createVerificationManifest("publish", {
base: "origin/trunk",
changedFiles: [path],
head: "HEAD",
}).find(({ id }) => id === "release-gate-tests");
expect(releaseGate?.applicable).toBe(true);
}
},
);

it.each([
"scripts/verification-manifest.mts",
"scripts/verification-change-classifier.mts",
Expand Down
Loading
Loading