semantic-js-mcp 0.10.0 → 0.10.1
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.
- package/.codex-plugin/plugin.json +1 -1
- package/CHANGELOG.md +11 -0
- package/README.md +13 -1
- package/docs/distribution.md +19 -0
- package/package.json +3 -2
- package/protocol.mjs +1 -1
- package/scripts/codex-plugin-verification.mjs +19 -0
- package/scripts/distribution-policy.mjs +1 -0
- package/scripts/documentation-contract.mjs +9 -1
- package/scripts/documentation-gate-smoke.mjs +21 -2
- package/scripts/documentation-gate.mjs +4 -0
- package/scripts/publish-workflow-smoke.mjs +62 -0
- package/scripts/release-contract.mjs +2 -0
- package/scripts/release-smoke.mjs +22 -1
- package/skills/semantic-navigation/references/protocol-literals.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,17 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.10.1] - 2026-07-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Publish release tags to npm through a protected GitHub Actions environment using short-lived OIDC credentials and automatic provenance.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Document and validate marketplace refresh before reinstalling an existing Codex plugin.
|
|
16
|
+
- Install and verify ripgrep in the trusted-publishing runner before executing the release gate.
|
|
17
|
+
|
|
7
18
|
## [0.10.0] - 2026-07-17
|
|
8
19
|
|
|
9
20
|
### Added
|
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ For each file, it identifies the owning workspace and uses the corresponding Typ
|
|
|
16
16
|
|
|
17
17
|
## Project Status
|
|
18
18
|
|
|
19
|
-
Version `0.10.
|
|
19
|
+
Version `0.10.1` is the current release. APIs and result contracts may evolve while the project remains on the `0.x` release line. See the [roadmap](ROADMAP.md) for areas under consideration.
|
|
20
20
|
|
|
21
21
|
## Installation
|
|
22
22
|
|
|
@@ -31,6 +31,18 @@ codex plugin add semantic-js-mcp@elnonathan
|
|
|
31
31
|
|
|
32
32
|
Codex CLI 0.144.4 or newer is required for npm-backed marketplace installation. Start a new Codex session after installation. The plugin bundles both the MCP server configuration and the semantic-navigation skill.
|
|
33
33
|
|
|
34
|
+
### Updating the Codex plugin
|
|
35
|
+
|
|
36
|
+
Codex installs from a local snapshot of each configured marketplace. Refresh that snapshot before reinstalling so `plugin add` resolves the version currently declared by the marketplace:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
codex plugin marketplace upgrade elnonathan
|
|
40
|
+
codex plugin add semantic-js-mcp@elnonathan
|
|
41
|
+
codex plugin list
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`plugin add` reinstalls the plugin; a separate removal is not required. Start a new Codex session after the command reports the expected version.
|
|
45
|
+
|
|
34
46
|
### MCP executable
|
|
35
47
|
|
|
36
48
|
Install the package globally when using an MCP host that accepts a command-based stdio configuration:
|
package/docs/distribution.md
CHANGED
|
@@ -11,6 +11,16 @@ codex plugin add semantic-js-mcp@elnonathan
|
|
|
11
11
|
|
|
12
12
|
The marketplace entry pins a concrete npm package version. Codex CLI 0.144.4 is the minimum verified client for npm-backed marketplace installation. A release updates the package version, plugin manifest, and marketplace entry together.
|
|
13
13
|
|
|
14
|
+
For an existing marketplace installation, refresh its local snapshot before reinstalling the plugin:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
codex plugin marketplace upgrade elnonathan
|
|
18
|
+
codex plugin add semantic-js-mcp@elnonathan
|
|
19
|
+
codex plugin list
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
`plugin add` reinstalls the plugin selected by the refreshed marketplace. Start a new Codex session after the listed version matches the release being installed.
|
|
23
|
+
|
|
14
24
|
## Executable
|
|
15
25
|
|
|
16
26
|
```bash
|
|
@@ -47,6 +57,7 @@ npm run check
|
|
|
47
57
|
npm run check:runtime
|
|
48
58
|
npm run check:documentation
|
|
49
59
|
npm run smoke:ci
|
|
60
|
+
npm run smoke:publish
|
|
50
61
|
npm run smoke:negative
|
|
51
62
|
npm run smoke:doctor
|
|
52
63
|
npm run smoke
|
|
@@ -68,6 +79,14 @@ The local release gate runs every configured source, runtime, semantic, evaluati
|
|
|
68
79
|
|
|
69
80
|
Postpublication verification requires an explicit version and the matching `v<version>` repository tag. It queries that immutable registry version, installs it with a fresh temporary npm cache and consumer project, verifies the installed executable and manifest, then runs the installed doctor to cover MCP startup, tool discovery, TypeScript evidence, and Vue navigation. It also installs the plugin from the tag-pinned marketplace inside a temporary `CODEX_HOME` and verifies the enabled plugin version. Temporary state is removed afterward. An unavailable registry, marketplace, or network is reported as `blocked`.
|
|
70
81
|
|
|
82
|
+
## npm Trusted Publishing
|
|
83
|
+
|
|
84
|
+
The `publish.yml` workflow publishes tags matching `v*` from a GitHub-hosted Node.js 24 runner. It requires the protected `npm-publish` environment, verifies that the tag exactly matches the package version, runs the complete release gate, and publishes through npm Trusted Publishing with OIDC. No long-lived npm token is used. npm generates provenance automatically for the public package.
|
|
85
|
+
|
|
86
|
+
Configure the npm trusted publisher for GitHub user `elnonathan`, repository `semantic-js-mcp`, workflow filename `publish.yml`, and environment `npm-publish`. Allow `npm publish` only. In package publishing access, require two-factor authentication and disallow tokens.
|
|
87
|
+
|
|
88
|
+
Create and push the matching `v<version>` tag only after the release commit is on `main` and its CI matrix passes. Approve the protected environment deployment, verify the published package, and then create the matching GitHub release.
|
|
89
|
+
|
|
71
90
|
## Continuous Integration
|
|
72
91
|
|
|
73
92
|
GitHub Actions runs the complete release gate on Node.js 22 and 24 across Ubuntu, macOS, and Windows. A second Linux matrix runs the same gate on Node.js 22 across Ubuntu, Fedora, Arch Linux, and openSUSE. The gate verifies ripgrep before running static checks, runtime resolution, documentation, CI policy, negative fixtures, doctor, TypeScript and Vue semantics, provider lifecycle, package installation, and the short benchmark.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "semantic-js-mcp",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "Semantic understanding of JavaScript codebases for AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|
|
@@ -44,13 +44,14 @@
|
|
|
44
44
|
"node": ">=22"
|
|
45
45
|
},
|
|
46
46
|
"scripts": {
|
|
47
|
-
"check": "npm run format:check && node --check protocol.mjs && node --check server.mjs && node --check cli.mjs && node --check lib/runtime.mjs && node --check lib/doctor.mjs && node --check lib/semantic-evidence.mjs && node --check lib/pending-requests.mjs && node --check lib/stable-collection.mjs && node --check scripts/generate-protocol-reference.mjs && node --check scripts/check-protocol-literals.mjs && node --check scripts/check-runtime.mjs && node --check scripts/documentation-contract.mjs && node --check scripts/documentation-gate.mjs && node --check scripts/documentation-gate-smoke.mjs && node --check scripts/semantic-js-mcp-ci.mjs && node --check scripts/ci-smoke.mjs && node --check scripts/negative-verification-smoke.mjs && node --check scripts/doctor-smoke.mjs && node --check scripts/smoke.mjs && node --check scripts/vue-smoke.mjs && node --check scripts/lifecycle-smoke.mjs && node --check scripts/lifecycle-memory-contract.mjs && node --check scripts/lifecycle-memory-observer.mjs && node --check scripts/lifecycle-memory-benchmark.mjs && node --check scripts/benchmark.mjs && node --check scripts/distribution-policy.mjs && node --check scripts/distribution-smoke.mjs && node --check scripts/release-contract.mjs && node --check scripts/release-verify.mjs && node --check scripts/release-smoke.mjs && node --check scripts/postpublication-smoke.mjs && node --check scripts/codex-plugin-verification.mjs && node --check scripts/agent-evaluation-contract.mjs && node --check scripts/agent-evaluation.mjs && node --check scripts/agent-evaluation-smoke.mjs && node --check scripts/repository-matrix-contract.mjs && node --check scripts/repository-matrix.mjs && node --check scripts/repository-matrix-smoke.mjs && node scripts/generate-protocol-reference.mjs --check && node scripts/check-protocol-literals.mjs && node scripts/documentation-gate-smoke.mjs",
|
|
47
|
+
"check": "npm run format:check && node --check protocol.mjs && node --check server.mjs && node --check cli.mjs && node --check lib/runtime.mjs && node --check lib/doctor.mjs && node --check lib/semantic-evidence.mjs && node --check lib/pending-requests.mjs && node --check lib/stable-collection.mjs && node --check scripts/generate-protocol-reference.mjs && node --check scripts/check-protocol-literals.mjs && node --check scripts/check-runtime.mjs && node --check scripts/documentation-contract.mjs && node --check scripts/documentation-gate.mjs && node --check scripts/documentation-gate-smoke.mjs && node --check scripts/semantic-js-mcp-ci.mjs && node --check scripts/ci-smoke.mjs && node --check scripts/publish-workflow-smoke.mjs && node --check scripts/negative-verification-smoke.mjs && node --check scripts/doctor-smoke.mjs && node --check scripts/smoke.mjs && node --check scripts/vue-smoke.mjs && node --check scripts/lifecycle-smoke.mjs && node --check scripts/lifecycle-memory-contract.mjs && node --check scripts/lifecycle-memory-observer.mjs && node --check scripts/lifecycle-memory-benchmark.mjs && node --check scripts/benchmark.mjs && node --check scripts/distribution-policy.mjs && node --check scripts/distribution-smoke.mjs && node --check scripts/release-contract.mjs && node --check scripts/release-verify.mjs && node --check scripts/release-smoke.mjs && node --check scripts/postpublication-smoke.mjs && node --check scripts/codex-plugin-verification.mjs && node --check scripts/agent-evaluation-contract.mjs && node --check scripts/agent-evaluation.mjs && node --check scripts/agent-evaluation-smoke.mjs && node --check scripts/repository-matrix-contract.mjs && node --check scripts/repository-matrix.mjs && node --check scripts/repository-matrix-smoke.mjs && node scripts/generate-protocol-reference.mjs --check && node scripts/check-protocol-literals.mjs && node scripts/documentation-gate-smoke.mjs",
|
|
48
48
|
"check:runtime": "node scripts/check-runtime.mjs",
|
|
49
49
|
"check:documentation": "node scripts/documentation-gate.mjs",
|
|
50
50
|
"doctor": "node cli.mjs doctor",
|
|
51
51
|
"ci:evaluate": "node scripts/semantic-js-mcp-ci.mjs",
|
|
52
52
|
"smoke": "node scripts/smoke.mjs",
|
|
53
53
|
"smoke:ci": "node scripts/ci-smoke.mjs",
|
|
54
|
+
"smoke:publish": "node scripts/publish-workflow-smoke.mjs",
|
|
54
55
|
"smoke:negative": "node scripts/negative-verification-smoke.mjs",
|
|
55
56
|
"smoke:doctor": "node scripts/doctor-smoke.mjs",
|
|
56
57
|
"smoke:vue": "node scripts/vue-smoke.mjs",
|
package/protocol.mjs
CHANGED
|
@@ -408,7 +408,7 @@ export const RESULT_SCHEMA = Object.freeze({
|
|
|
408
408
|
VERSION: 7,
|
|
409
409
|
});
|
|
410
410
|
|
|
411
|
-
export const SERVER_VERSION = "0.10.
|
|
411
|
+
export const SERVER_VERSION = "0.10.1";
|
|
412
412
|
|
|
413
413
|
export const REQUIRED_RUNTIME_COMPONENT = Object.freeze({
|
|
414
414
|
TYPESCRIPT_LANGUAGE_SERVER: "typescript-language-server/lib/cli.mjs",
|
|
@@ -71,6 +71,25 @@ export async function verifyCodexPlugin({version, workspace, spawn, runCommand})
|
|
|
71
71
|
];
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
const upgrade = await execute(CODEX_DISTRIBUTION.EXECUTABLE, [
|
|
75
|
+
CODEX_DISTRIBUTION.PLUGIN_COMMAND,
|
|
76
|
+
CODEX_DISTRIBUTION.MARKETPLACE_COMMAND,
|
|
77
|
+
CODEX_DISTRIBUTION.UPGRADE_COMMAND,
|
|
78
|
+
CODEX_DISTRIBUTION.MARKETPLACE_NAME,
|
|
79
|
+
CODEX_DISTRIBUTION.JSON_ARGUMENT,
|
|
80
|
+
]);
|
|
81
|
+
if (upgrade.exitCode !== CI_EXIT_CODE.PASS) {
|
|
82
|
+
const unavailable = upgrade.exitCode === undefined || networkUnavailable(upgrade);
|
|
83
|
+
return [
|
|
84
|
+
check(
|
|
85
|
+
RELEASE_CHECK.CODEX_MARKETPLACE,
|
|
86
|
+
unavailable ? CI_STATUS.BLOCKED : CI_STATUS.FAIL,
|
|
87
|
+
unavailable ? RELEASE_REASON.CODEX_MARKETPLACE_UNAVAILABLE : RELEASE_REASON.CODEX_MARKETPLACE_FAILED,
|
|
88
|
+
{marketplaceRef, message: failureMessage(upgrade)},
|
|
89
|
+
),
|
|
90
|
+
];
|
|
91
|
+
}
|
|
92
|
+
|
|
74
93
|
const checks = [check(RELEASE_CHECK.CODEX_MARKETPLACE, CI_STATUS.PASS, RELEASE_REASON.CHECK_COMPLETED, {marketplaceRef})];
|
|
75
94
|
const installation = await execute(CODEX_DISTRIBUTION.EXECUTABLE, [
|
|
76
95
|
CODEX_DISTRIBUTION.PLUGIN_COMMAND,
|
|
@@ -12,7 +12,15 @@ export const PUBLIC_ROOT_DOCUMENT = Object.freeze(["CHANGELOG.md", "CONTRIBUTING
|
|
|
12
12
|
export const PUBLIC_DOCUMENT_DIRECTORY = Object.freeze(["docs", "skills"]);
|
|
13
13
|
|
|
14
14
|
export const DOCUMENTATION_REQUIREMENT = Object.freeze({
|
|
15
|
-
README_HEADINGS: Object.freeze([
|
|
15
|
+
README_HEADINGS: Object.freeze([
|
|
16
|
+
"Installation",
|
|
17
|
+
"Updating the Codex plugin",
|
|
18
|
+
"Runtime",
|
|
19
|
+
"Verification",
|
|
20
|
+
"Current Limitations",
|
|
21
|
+
"Reporting Problems",
|
|
22
|
+
]),
|
|
23
|
+
README_LITERALS: Object.freeze(["codex plugin marketplace upgrade elnonathan", "codex plugin add semantic-js-mcp@elnonathan"]),
|
|
16
24
|
GETTING_STARTED_HEADINGS: Object.freeze([
|
|
17
25
|
"Trace A Symbol",
|
|
18
26
|
"Review A Security-Sensitive Change",
|
|
@@ -6,7 +6,7 @@ import {evaluateDocumentation} from "./documentation-gate.mjs";
|
|
|
6
6
|
|
|
7
7
|
const headingText = (headings) => headings.map((heading) => `## ${heading}`).join("\n");
|
|
8
8
|
const valid = {
|
|
9
|
-
[DOCUMENTATION_FILE.README]: `${headingText(DOCUMENTATION_REQUIREMENT.README_HEADINGS)}\n${DOCUMENTATION_REQUIREMENT.README_LINKS.map((link) => `[doc](${link})`).join("\n")}`,
|
|
9
|
+
[DOCUMENTATION_FILE.README]: `${headingText(DOCUMENTATION_REQUIREMENT.README_HEADINGS)}\n${DOCUMENTATION_REQUIREMENT.README_LINKS.map((link) => `[doc](${link})`).join("\n")}\n${DOCUMENTATION_REQUIREMENT.README_LITERALS.join("\n")}`,
|
|
10
10
|
[DOCUMENTATION_FILE.GETTING_STARTED]: `${headingText(DOCUMENTATION_REQUIREMENT.GETTING_STARTED_HEADINGS)}\n${DOCUMENTATION_REQUIREMENT.GETTING_STARTED_LITERALS.join("\n")}`,
|
|
11
11
|
[DOCUMENTATION_FILE.CONTRIBUTING]: "# Contributing",
|
|
12
12
|
[DOCUMENTATION_FILE.SECURITY]: "# Security",
|
|
@@ -46,9 +46,28 @@ strictEqual(
|
|
|
46
46
|
"Missing canonical example literal was accepted",
|
|
47
47
|
);
|
|
48
48
|
|
|
49
|
+
const missingMarketplaceUpgrade = {
|
|
50
|
+
...valid,
|
|
51
|
+
[DOCUMENTATION_FILE.README]: valid[DOCUMENTATION_FILE.README].replace(DOCUMENTATION_REQUIREMENT.README_LITERALS[0], ""),
|
|
52
|
+
};
|
|
53
|
+
strictEqual(
|
|
54
|
+
evaluateDocumentation(missingMarketplaceUpgrade).some(
|
|
55
|
+
(finding) =>
|
|
56
|
+
finding.reason === DOCUMENTATION_REASON.LITERAL_MISSING && finding.literal === DOCUMENTATION_REQUIREMENT.README_LITERALS[0],
|
|
57
|
+
),
|
|
58
|
+
true,
|
|
59
|
+
"Missing marketplace upgrade guidance was accepted",
|
|
60
|
+
);
|
|
61
|
+
|
|
49
62
|
process.stdout.write(
|
|
50
63
|
`${JSON.stringify(
|
|
51
|
-
{
|
|
64
|
+
{
|
|
65
|
+
validDocumentation: "pass",
|
|
66
|
+
missingHeading: "rejected",
|
|
67
|
+
missingLiteral: "rejected",
|
|
68
|
+
missingMarketplaceUpgrade: "rejected",
|
|
69
|
+
privateCoordination: "rejected",
|
|
70
|
+
},
|
|
52
71
|
null,
|
|
53
72
|
2,
|
|
54
73
|
)}\n`,
|
|
@@ -52,6 +52,10 @@ export function evaluateDocumentation(documents) {
|
|
|
52
52
|
if (readme.includes(`](${link})`)) continue;
|
|
53
53
|
findings.push({file: DOCUMENTATION_FILE.README, reason: DOCUMENTATION_REASON.LINK_MISSING, link});
|
|
54
54
|
}
|
|
55
|
+
for (const literal of DOCUMENTATION_REQUIREMENT.README_LITERALS) {
|
|
56
|
+
if (readme.includes(literal)) continue;
|
|
57
|
+
findings.push({file: DOCUMENTATION_FILE.README, reason: DOCUMENTATION_REASON.LITERAL_MISSING, literal});
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
60
|
|
|
57
61
|
const gettingStarted = documents[DOCUMENTATION_FILE.GETTING_STARTED];
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import {deepStrictEqual, strictEqual} from "node:assert";
|
|
4
|
+
import {readFile} from "node:fs/promises";
|
|
5
|
+
import {fileURLToPath} from "node:url";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import {parse} from "yaml";
|
|
8
|
+
|
|
9
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
|
+
const workflowFile = path.join(root, ".github", "workflows", "publish.yml");
|
|
11
|
+
const workflowText = await readFile(workflowFile, "utf8");
|
|
12
|
+
const workflow = parse(workflowText);
|
|
13
|
+
const publish = workflow.jobs?.publish;
|
|
14
|
+
const steps = publish?.steps || [];
|
|
15
|
+
const setupNode = steps.find((step) => step.uses === "actions/setup-node@v6");
|
|
16
|
+
const commands = steps.flatMap((step) => (typeof step.run === "string" ? [step.run] : []));
|
|
17
|
+
|
|
18
|
+
deepStrictEqual(Object.keys(workflow.on || {}), ["push"], "Publish workflow must only run from tag pushes");
|
|
19
|
+
deepStrictEqual(workflow.on?.push?.tags, ["v*"], "Publish workflow must run only for release tags");
|
|
20
|
+
deepStrictEqual(
|
|
21
|
+
workflow.permissions,
|
|
22
|
+
{contents: "read", "id-token": "write"},
|
|
23
|
+
"Publish workflow must grant only repository read and OIDC permissions",
|
|
24
|
+
);
|
|
25
|
+
strictEqual(publish?.if, "github.repository == 'elnonathan/semantic-js-mcp'", "Publishing must be restricted to the canonical repository");
|
|
26
|
+
strictEqual(publish?.["runs-on"], "ubuntu-latest", "Publishing must use a GitHub-hosted runner");
|
|
27
|
+
strictEqual(publish?.environment, "npm-publish", "Publishing must use the protected npm environment");
|
|
28
|
+
strictEqual(workflow.concurrency?.["cancel-in-progress"], false, "An active publication must never be cancelled by another tag");
|
|
29
|
+
strictEqual(setupNode?.with?.["node-version"], 24, "Publishing must use Node.js 24");
|
|
30
|
+
strictEqual(setupNode?.with?.["registry-url"], "https://registry.npmjs.org", "Publishing must target npmjs.org");
|
|
31
|
+
strictEqual(setupNode?.with?.["package-manager-cache"], false, "Release builds must not use a package-manager cache");
|
|
32
|
+
strictEqual(
|
|
33
|
+
commands.includes("sudo apt-get update && sudo apt-get install --yes ripgrep"),
|
|
34
|
+
true,
|
|
35
|
+
"Publishing must install the required ripgrep executable",
|
|
36
|
+
);
|
|
37
|
+
strictEqual(commands.includes("rg --version"), true, "Publishing must verify ripgrep before the release gate");
|
|
38
|
+
strictEqual(commands.includes("npm install --global npm@11.17.0"), true, "Publishing must install the verified npm CLI");
|
|
39
|
+
strictEqual(commands.includes("npm ci"), true, "Publishing must install the locked dependency tree");
|
|
40
|
+
strictEqual(commands.includes("npm run release:verify"), true, "Publishing must run the complete release gate");
|
|
41
|
+
strictEqual(commands.includes("npm publish --access public"), true, "Publishing must use the public OIDC publish path");
|
|
42
|
+
strictEqual(
|
|
43
|
+
commands.some((command) => command.includes("GITHUB_REF_NAME") && command.includes("package.json")),
|
|
44
|
+
true,
|
|
45
|
+
"Publishing must reject a tag that differs from the package version",
|
|
46
|
+
);
|
|
47
|
+
strictEqual(workflowText.includes("NODE_AUTH_TOKEN"), false, "OIDC publishing must not use an npm token");
|
|
48
|
+
strictEqual(workflowText.includes("secrets."), false, "OIDC publishing must not read repository secrets");
|
|
49
|
+
|
|
50
|
+
process.stdout.write(
|
|
51
|
+
`${JSON.stringify(
|
|
52
|
+
{
|
|
53
|
+
workflow: "publish.yml",
|
|
54
|
+
trigger: "release-tags",
|
|
55
|
+
authentication: "oidc",
|
|
56
|
+
environment: publish.environment,
|
|
57
|
+
tokenSecret: "absent",
|
|
58
|
+
},
|
|
59
|
+
null,
|
|
60
|
+
2,
|
|
61
|
+
)}\n`,
|
|
62
|
+
);
|
|
@@ -10,6 +10,7 @@ export const RELEASE_CHECK = Object.freeze({
|
|
|
10
10
|
RUNTIME: "runtime",
|
|
11
11
|
DOCUMENTATION: "documentation",
|
|
12
12
|
CI_POLICY: "ci-policy",
|
|
13
|
+
PUBLISH_WORKFLOW: "publish-workflow",
|
|
13
14
|
NEGATIVE_VERIFICATION: "negative-verification",
|
|
14
15
|
DOCTOR: "doctor",
|
|
15
16
|
TYPESCRIPT_SMOKE: "typescript-smoke",
|
|
@@ -57,6 +58,7 @@ export const RELEASE_LOCAL_CHECKS = Object.freeze([
|
|
|
57
58
|
Object.freeze({name: RELEASE_CHECK.RUNTIME, npmScript: "check:runtime"}),
|
|
58
59
|
Object.freeze({name: RELEASE_CHECK.DOCUMENTATION, npmScript: "check:documentation"}),
|
|
59
60
|
Object.freeze({name: RELEASE_CHECK.CI_POLICY, npmScript: "smoke:ci"}),
|
|
61
|
+
Object.freeze({name: RELEASE_CHECK.PUBLISH_WORKFLOW, npmScript: "smoke:publish"}),
|
|
60
62
|
Object.freeze({name: RELEASE_CHECK.NEGATIVE_VERIFICATION, npmScript: "smoke:negative"}),
|
|
61
63
|
Object.freeze({name: RELEASE_CHECK.DOCTOR, npmScript: "smoke:doctor"}),
|
|
62
64
|
Object.freeze({name: RELEASE_CHECK.TYPESCRIPT_SMOKE, npmScript: "smoke"}),
|
|
@@ -81,7 +81,11 @@ try {
|
|
|
81
81
|
calls[0].args.includes(`${CODEX_DISTRIBUTION.VERSION_REF_PREFIX}${version}`),
|
|
82
82
|
"Codex marketplace verification did not use an immutable version ref",
|
|
83
83
|
);
|
|
84
|
-
assert(
|
|
84
|
+
assert(
|
|
85
|
+
calls[1].args.includes(CODEX_DISTRIBUTION.UPGRADE_COMMAND) && calls[1].args.includes(CODEX_DISTRIBUTION.MARKETPLACE_NAME),
|
|
86
|
+
"Codex marketplace verification omitted the configured snapshot refresh",
|
|
87
|
+
);
|
|
88
|
+
assert(calls[2].args.includes(CODEX_DISTRIBUTION.PLUGIN_SELECTOR), "Codex verification used the wrong plugin selector");
|
|
85
89
|
assert(
|
|
86
90
|
calls.every((call) => call.options.env[CODEX_DISTRIBUTION.HOME_ENVIRONMENT_VARIABLE].startsWith(codexWorkspace)),
|
|
87
91
|
"Codex verification did not isolate its state under the temporary workspace",
|
|
@@ -105,6 +109,22 @@ try {
|
|
|
105
109
|
networkChecks[0].reason === RELEASE_REASON.CODEX_MARKETPLACE_UNAVAILABLE,
|
|
106
110
|
"Unavailable Codex marketplace network used the wrong reason",
|
|
107
111
|
);
|
|
112
|
+
|
|
113
|
+
let upgradeCall = 0;
|
|
114
|
+
const upgradeNetworkChecks = await verifyCodexPlugin({
|
|
115
|
+
version,
|
|
116
|
+
workspace: codexWorkspace,
|
|
117
|
+
runCommand: async () => {
|
|
118
|
+
upgradeCall++;
|
|
119
|
+
if (upgradeCall === 1) return {exitCode: CI_EXIT_CODE.PASS, stdout: "{}", stderr: ""};
|
|
120
|
+
return {exitCode: CI_EXIT_CODE.FAIL, stdout: "", stderr: "network is unreachable"};
|
|
121
|
+
},
|
|
122
|
+
});
|
|
123
|
+
assert(upgradeNetworkChecks[0].status === CI_STATUS.BLOCKED, "Unavailable marketplace upgrade was not blocked");
|
|
124
|
+
assert(
|
|
125
|
+
upgradeNetworkChecks[0].reason === RELEASE_REASON.CODEX_MARKETPLACE_UNAVAILABLE,
|
|
126
|
+
"Unavailable marketplace upgrade used the wrong reason",
|
|
127
|
+
);
|
|
108
128
|
} finally {
|
|
109
129
|
await rm(codexWorkspace, {recursive: true, force: true});
|
|
110
130
|
}
|
|
@@ -116,6 +136,7 @@ process.stdout.write(
|
|
|
116
136
|
missingPublishedVersion: "blocked",
|
|
117
137
|
isolatedCodexPluginInstallation: "ok",
|
|
118
138
|
unavailableCodexMarketplace: "blocked",
|
|
139
|
+
unavailableCodexMarketplaceUpgrade: "blocked",
|
|
119
140
|
},
|
|
120
141
|
null,
|
|
121
142
|
2,
|