Skip to content
Open
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
41 changes: 26 additions & 15 deletions .github/workflows/publish-contracts-abi-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ permissions:

jobs:
publish:
runs-on: ['self-hosted', 'org', 'npm-publish']
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
Expand All @@ -51,20 +51,11 @@ jobs:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Akeyless Get Secrets
id: get_auth_token
uses: docker://us-west1-docker.pkg.dev/devopsre/akeyless-public/akeyless-action:latest
with:
api-url: https://api.gateway.akeyless.celo-networks-dev.org
access-id: p-kf9vjzruht6l
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setup-node registry-url creates .npmrc conflicting with OIDC

Medium Severity

The actions/setup-node step with registry-url generates an .npmrc file containing //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}. Since NODE_AUTH_TOKEN was removed from the env vars, this resolves to empty, which can prevent npm from falling through to OIDC authentication — a known issue tracked in actions/setup-node#1440.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

static-secrets: '{"/static-secrets/NPM/npm-publish-token":"NPM_TOKEN"}'

# Setup .npmrc file to publish to npm
- uses: actions/setup-node@v4
with:
node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
#scope: '@celo'
node-version: '20.x'
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node.js 20.x doesn't meet OIDC minimum version requirement

High Severity

npm OIDC trusted publishing requires Node.js 22.14.0 or higher, but node-version is set to '20.x'. The version was upgraded from 18.x to 20.x, but that's still insufficient for trusted publishing. Both npm publish steps will fail authentication because the OIDC token exchange mechanism is not available on Node.js 20.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is not true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Use a Truffle-supported Node version in this workflow

This job still runs yarn build --include-dependencies, which reaches packages/protocol's build script and shells out to truffle compile in packages/protocol/scripts/build.ts. The repo is pinned to truffle@5.9.0 (packages/protocol/package.json), and Truffle only added Node 20 support in later releases, so bumping this runner from 18.x to 20.x can break the compile step before either package is published. That would block every contracts/abis release until Truffle is upgraded or the workflow stays on Node 18.

Useful? React with 👍 / 👎.


- name: 'Setup yarn'
shell: bash
Expand Down Expand Up @@ -101,6 +92,28 @@ jobs:
- name: 'Get git commit hash'
id: get_COMMIT_HASH
run: echo "COMMIT_HASH=$(git rev-parse --short HEAD)" >> $GITHUB_ENV

- name: Update npm for OIDC trusted publishing (v11.5.1)
run: npm install -g npm@11.5.1
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OIDC trusted publishing unsupported on self-hosted runners

High Severity

npm OIDC trusted publishing currently only supports GitHub-hosted runners, not self-hosted ones. This job uses runs-on: ['self-hosted', 'org', 'npm-publish']. The npm registry will reject the OIDC token from a self-hosted runner because it verifies the runner_environment claim. The old token-based auth that worked on self-hosted runners has been removed.

Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OIDC trusted publishing doesn't authenticate npm dist-tag add

High Severity

npm OIDC trusted publishing only authenticates the npm publish command. The npm dist-tag add calls at lines 110 and 127 will fail with auth errors because OIDC doesn't cover that command (tracked as npm/cli#8547). Previously, NODE_AUTH_TOKEN provided a persistent token that worked for both operations. After a successful publish, the step will error out on dist-tag add, leaving packages published but untagged with the commit hash.

Additional Locations (1)
Fix in Cursor Fix in Web

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commented

# Fallback: ensure package.json has version (prepare script may not persist in CI)
- name: Ensure package.json has version
run: |
for pkg in packages/protocol/contracts packages/protocol/abis; do
node -e "
const fs = require('fs');
const pkgPath = process.argv[1] + '/package.json';
const pkg = JSON.parse(fs.readFileSync(pkgPath));
if (!pkg.version) {
pkg.version = process.env.RELEASE_VERSION || '0.0.0-dry-run';
pkg.private = false;
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
}
" "$pkg"
done
env:
RELEASE_VERSION: ${{ env.RELEASE_VERSION }}

- name: Publish @celo/contracts
run: |
cat package.json
Expand All @@ -110,12 +123,11 @@ jobs:
echo "Dry run mode, exiting successfully."
exit 0
fi
npm dist-tag add @celo/contracts@$RELEASE_VERSION $COMMIT_HASH
# npm dist-tag add @celo/contracts@$RELEASE_VERSION $COMMIT_HASH
working-directory: packages/protocol/contracts
env:
RELEASE_TYPE: --tag ${{ env.RELEASE_TYPE != '' && env.RELEASE_TYPE || 'canary' }}
RELEASE_VERSION: ${{ env.RELEASE_VERSION }}
NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }}
DRY_RUN: ${{ env.RELEASE_VERSION == '' && '--dry-run' || '' }}
COMMIT_HASH: ${{ env.COMMIT_HASH }}
Comment on lines 128 to 132
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Provide auth for dist-tag updates

This change removes NODE_AUTH_TOKEN from the publish step env while still running npm dist-tag add in non-dry-run releases, so the tag update now runs without explicit npm credentials. In this workflow that path is taken whenever RELEASE_VERSION is set, and npm dist-tag is a registry write operation (npm dist-tag --help: add, rm, ls) that fails unauthenticated (403/ENEEDAUTH), which would make release jobs fail after publishing and skip the commit-hash dist-tagging.

Useful? React with 👍 / 👎.


Expand All @@ -128,11 +140,10 @@ jobs:
echo "Dry run mode, exiting successfully."
exit 0
fi
npm dist-tag add @celo/abis@$RELEASE_VERSION $COMMIT_HASH
# npm dist-tag add @celo/abis@$RELEASE_VERSION $COMMIT_HASH
working-directory: packages/protocol/abis
env:
RELEASE_TYPE: --tag ${{ env.RELEASE_TYPE != '' && env.RELEASE_TYPE || 'canary' }}
RELEASE_VERSION: ${{ env.RELEASE_VERSION }}
NODE_AUTH_TOKEN: ${{ env.NPM_TOKEN }}
DRY_RUN: ${{ env.RELEASE_VERSION == '' && '--dry-run' || '' }}
COMMIT_HASH: ${{ env.COMMIT_HASH }}
5 changes: 5 additions & 0 deletions packages/protocol/abis/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@
"./dist",
"!**/*.js.map"
],
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/",
"provenance": true
},
"exports": {
".": {
"import": "./dist/esm/index.js",
Expand Down
5 changes: 5 additions & 0 deletions packages/protocol/contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@
"url": "https://github.com/celo-org/celo-monorepo.git",
"directory": "packages/protocol/contracts"
},
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org/",
"provenance": true
},
"scripts": {},
"dependencies": {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
BuildTarget,
CONTRACTS_08_PACKAGE_DESTINATION_DIR,
CONTRACTS_08_SOURCE_DIR,
CONTRACTS_PACKAGE_SRC_DIR,
// CONTRACTS_PACKAGE_SRC_DIR - unused: we use process.cwd() for correct path resolution in CI
PublishContracts,
TSCONFIG_PATH,
} from './consts'
Expand Down Expand Up @@ -260,38 +260,41 @@ function processRawJsonsAndPrepareExports() {
return exports
}

const DRY_RUN_VERSION = '0.0.0-dry-run'

function prepareAbisPackageJson(exports: Exports) {
log('Preparing @celo/abis package.json')
const packageJsonPath = path.join(ABIS_PACKAGE_SRC_DIR, 'package.json')
// Use process.cwd() so paths are correct when run with working-directory: packages/protocol (e.g. in CI)
const packageJsonPath = path.resolve(process.cwd(), 'abis', 'package.json')

const version = process.env.RELEASE_VERSION || DRY_RUN_VERSION
if (process.env.RELEASE_VERSION) {
log('Replacing @celo/abis version with RELEASE_VERSION)')

replacePackageVersionAndMakePublic(packageJsonPath, (json) => {
log('Setting @celo/abis exports')
json.exports = exports
})

return
log('Replacing @celo/abis version with RELEASE_VERSION')
} else {
log(`Using placeholder version ${DRY_RUN_VERSION} for dry run`)
}

log('Skipping @celo/abis package.json preparation (no RELEASE_VERSION provided)')
replacePackageVersionAndMakePublic(packageJsonPath, version, (json) => {
log('Setting @celo/abis exports')
json.exports = exports
})
}

function prepareContractsPackage() {
const contracts08CpCommand = `cp -r ${CONTRACTS_08_SOURCE_DIR} ${CONTRACTS_08_PACKAGE_DESTINATION_DIR}`
log(contracts08CpCommand)
child_process.execSync(contracts08CpCommand)

const version = process.env.RELEASE_VERSION || DRY_RUN_VERSION
if (process.env.RELEASE_VERSION) {
log('Replacing @celo/contracts version with RELEASE_VERSION)')
const packageJsonPath = path.join(CONTRACTS_PACKAGE_SRC_DIR, 'package.json')
replacePackageVersionAndMakePublic(packageJsonPath)

return
log('Replacing @celo/contracts version with RELEASE_VERSION')
} else {
log(`Using placeholder version ${DRY_RUN_VERSION} for dry run`)
}

log('Skipping @celo/contracts package.json preparation (no RELEASE_VERSION provided)')
// Use process.cwd() so paths are correct when run with working-directory: packages/protocol (e.g. in CI)
const packageJsonPath = path.resolve(process.cwd(), 'contracts', 'package.json')
replacePackageVersionAndMakePublic(packageJsonPath, version)
}

function lsRecursive(dir: string): string[] {
Expand Down
10 changes: 6 additions & 4 deletions packages/protocol/scripts/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,17 +121,19 @@ export function getReleaseTypeFromSemVer(version: SemVer): string | number {

export function replacePackageVersionAndMakePublic(
packageJsonPath: string,
version?: string,
onDone?: (json: JSON) => void
) {
const json: JSON = JSON.parse(fs.readFileSync(packageJsonPath).toString())

if (process.env.RELEASE_VERSION) {
console.info(`Replacing ${json.name as string} version with provided RELEASE_VERSION`)
const effectiveVersion = version ?? process.env.RELEASE_VERSION
if (effectiveVersion) {
console.info(`Replacing ${json.name as string} version with ${effectiveVersion}`)

json.version = process.env.RELEASE_VERSION
json.version = effectiveVersion
json.private = false
} else {
console.info('No RELEASE_VERSION provided')
console.info('No version provided')
}

if (onDone !== undefined) {
Expand Down
Loading