Skip to content

Commit f6d37b5

Browse files
[codex] Improve Socket score drivers (#39)
* Improve Socket score drivers * Address review feedback
1 parent 4eca539 commit f6d37b5

14 files changed

Lines changed: 613 additions & 125 deletions

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Keep this file aligned with the trusted GitHub maintainers for the repository.
2+
* @andrewkoltsov

.github/workflows/release.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,24 @@ jobs:
8282
if: steps.npm_status.outputs.published != 'true'
8383
run: npm publish --provenance
8484

85+
- name: Verify published package attestations
86+
env:
87+
PACKAGE_NAME: librus-sdk
88+
PACKAGE_VERSION: ${{ steps.package_metadata.outputs.version }}
89+
run: |
90+
for attempt in 1 2 3; do
91+
if node ./scripts/verify-published-package.mjs "$PACKAGE_NAME" "$PACKAGE_VERSION"; then
92+
exit 0
93+
fi
94+
95+
if [ "$attempt" -eq 3 ]; then
96+
echo "Published package metadata for $PACKAGE_NAME@$PACKAGE_VERSION did not expose attestations/signatures after 3 attempts." >&2
97+
exit 1
98+
fi
99+
100+
sleep 5
101+
done
102+
85103
- name: Check whether GitHub Release already exists
86104
id: release_status
87105
env:

CHANGELOG.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
66

77
## [Unreleased]
88

9+
### Added
10+
11+
- Release automation now verifies the published npm package still exposes
12+
provenance attestations and registry signatures after
13+
`npm publish --provenance`.
14+
- Repository ownership metadata now includes `.github/CODEOWNERS`, and release
15+
docs now spell out maintainer continuity expectations.
16+
17+
### Changed
18+
19+
- CLI startup now uses Node's built-in `.env` file loader instead of shipping
20+
`dotenv` as a runtime dependency.
21+
- CLI text rendering now uses an internal formatter instead of `cliui`,
22+
reducing the published runtime dependency footprint while preserving the
23+
existing text/json command surface.
24+
925
## [0.3.2] - 2026-04-01
1026

1127
### Fixed

docs/releasing.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ The release workflow in
3434
- confirm the pushed tag matches `package.json`
3535
- require the tagged commit to be reachable from `origin/master`
3636
- publish to npm if that version is not already present
37+
- verify the published npm package still exposes provenance attestations and
38+
registry signatures after `npm publish --provenance`
3739
- create the GitHub Release from the matching `CHANGELOG.md` section
3840

3941
## Release Notes Policy
@@ -69,6 +71,17 @@ continues to publish to npmjs only.
6971
6. Push the tag to GitHub.
7072
7. Verify that the release workflow publishes the package and creates the
7173
GitHub Release.
74+
8. Confirm the workflow's published-package verification step succeeds.
75+
76+
## Maintainer Continuity
77+
78+
- Keep `.github/CODEOWNERS` aligned with the trusted GitHub maintainers who can
79+
review and land changes.
80+
- Keep at least two trusted maintainers on GitHub and npm before enforcing an
81+
approving-review requirement on `master`, so branch protection does not
82+
deadlock releases.
83+
- After maintainers change, re-check `master` branch protection so the required
84+
status checks still include the CI validation gate and CodeQL analysis.
7285

7386
## Homepage Value For Badge Evidence
7487

package-lock.json

Lines changed: 15 additions & 53 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,17 +64,15 @@
6464
"license": "MIT",
6565
"dependencies": {
6666
"@valibot/to-json-schema": "^1.6.0",
67-
"cliui": "^9.0.1",
6867
"commander": "^14.0.0",
69-
"dotenv": "^17.2.3",
7068
"fetch-cookie": "^3.1.0",
7169
"parse5": "^8.0.0",
7270
"tough-cookie": "^6.0.1",
7371
"valibot": "^1.3.1"
7472
},
7573
"devDependencies": {
7674
"@eslint/js": "^10.0.1",
77-
"@types/node": "^25.5.0",
75+
"@types/node": "^20.19.37",
7876
"@vitest/coverage-v8": "^4.1.2",
7977
"eslint": "^10.1.0",
8078
"eslint-config-prettier": "^10.1.8",
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import { execFileSync } from "node:child_process";
2+
import { resolve } from "node:path";
3+
import { pathToFileURL } from "node:url";
4+
5+
export function assertPublishedPackageSecurityMetadata(metadata, packageSpec) {
6+
if (!metadata || typeof metadata !== "object") {
7+
throw new Error(
8+
`npm view returned no package metadata for ${packageSpec}.`,
9+
);
10+
}
11+
12+
const dist =
13+
"dist" in metadata && metadata.dist && typeof metadata.dist === "object"
14+
? metadata.dist
15+
: null;
16+
const attestations =
17+
dist &&
18+
"attestations" in dist &&
19+
dist.attestations &&
20+
typeof dist.attestations === "object"
21+
? dist.attestations
22+
: null;
23+
const provenance =
24+
attestations &&
25+
"provenance" in attestations &&
26+
attestations.provenance &&
27+
typeof attestations.provenance === "object"
28+
? attestations.provenance
29+
: null;
30+
const signatures =
31+
dist && "signatures" in dist && Array.isArray(dist.signatures)
32+
? dist.signatures
33+
: [];
34+
35+
if (!attestations || typeof attestations.url !== "string") {
36+
throw new Error(
37+
`Published package ${packageSpec} is missing npm attestations metadata.`,
38+
);
39+
}
40+
41+
if (!provenance || typeof provenance.predicateType !== "string") {
42+
throw new Error(
43+
`Published package ${packageSpec} is missing provenance details.`,
44+
);
45+
}
46+
47+
if (signatures.length === 0) {
48+
throw new Error(
49+
`Published package ${packageSpec} is missing npm registry signatures.`,
50+
);
51+
}
52+
}
53+
54+
export function verifyPublishedPackage(packageName, packageVersion) {
55+
const packageSpec = packageVersion
56+
? `${packageName}@${packageVersion}`
57+
: packageName;
58+
const stdout = fetchPublishedPackageMetadata(packageSpec);
59+
const metadata = JSON.parse(stdout);
60+
61+
assertPublishedPackageSecurityMetadata(metadata, packageSpec);
62+
}
63+
64+
export function fetchPublishedPackageMetadata(packageSpec) {
65+
try {
66+
return execFileSync("npm", ["view", packageSpec, "--json"], {
67+
encoding: "utf8",
68+
stdio: ["ignore", "pipe", "pipe"],
69+
});
70+
} catch (error) {
71+
const message =
72+
error instanceof Error && error.message
73+
? error.message
74+
: "Unknown npm view failure.";
75+
76+
throw new Error(
77+
`Failed to fetch package metadata for ${packageSpec} from npm registry: ${message}`,
78+
{ cause: error },
79+
);
80+
}
81+
}
82+
83+
if (import.meta.url === pathToFileURL(resolve(process.argv[1] ?? "")).href) {
84+
const [, , packageName, packageVersion] = process.argv;
85+
86+
if (!packageName) {
87+
console.error(
88+
"Usage: node ./scripts/verify-published-package.mjs <package-name> [version]",
89+
);
90+
process.exitCode = 1;
91+
} else {
92+
verifyPublishedPackage(packageName, packageVersion);
93+
}
94+
}

0 commit comments

Comments
 (0)