From 62453126550d9d1f8fdf0161d85334864a91d366 Mon Sep 17 00:00:00 2001 From: Lutfi Garzon Date: Tue, 21 Apr 2026 13:21:14 -0500 Subject: [PATCH] feat: trigger release for OIDC, security updates, and CI pipeline fixes This PR resolves the issue where `semantic-release` was not producing a build or including artifacts. It also dynamically injects the CLI version and strictly enforces Angular Conventional Commits to prevent ignored releases like the previous OIDC features. --- .pi/agent/AGENTS.md | 17 +++- .releaserc.json | 21 ++++- package-lock.json | 188 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 7 ++ src/cli.ts | 7 +- 5 files changed, 236 insertions(+), 4 deletions(-) diff --git a/.pi/agent/AGENTS.md b/.pi/agent/AGENTS.md index cedb02f..55ea1f6 100644 --- a/.pi/agent/AGENTS.md +++ b/.pi/agent/AGENTS.md @@ -11,7 +11,7 @@ guidelines: - "Hardware Integrity: Any changes to src/core/bridge.swift require a re-compile and re-sign of vault-bridge." - "Testing & TDD: Strictly adhere to TDD (Red-Green-Refactor). No production code without a failing test. Maintain >80% coverage across all metrics (Lines, Branches, Functions, Statements)." - "Workflow Gate: Run `npx vitest run --coverage` before any hand-off or PR. The test suite is the final authority on code quality." - - "Versioning & Commits: Follow Conventional Commits (`feat:`, `fix:`, `chore:`, `ci:`, etc.) strictly. `semantic-release` automates version bumps and NPM publishing." + - "Versioning & Commits: YOU MUST follow Angular Conventional Commits EXACTLY. Use lowercase types and a colon (e.g., `feat: `, `fix: `). Never use uppercase/slashes like `Feat/OIDC`. PR titles must use this format so Squash & Merge triggers `semantic-release`." - "Biometrics Compilation: The Swift bridge (`vault-bridge`) is automatically compiled on the user's machine during the `vault eb` (`biometrics`) command using local ad-hoc signing. Maintain this auto-compile flow for NPM distribution." - "Bridge & Entitlements: `src/core/bridge.swift` and `vault.entitlements` must be included in the `files` array of `package.json` to ensure they are shipped in the NPM package for local compilation." - "CI/CD & Publishing: NPM publishing uses OIDC provenance via the `npm-publish` GitHub environment. Main branch is protected; always use Pull Requests." @@ -19,3 +19,18 @@ guidelines: --- # Vault Project Guidelines This file ensures that any agent or contributor adheres to the cryptographic and architectural standards of the Vault CLI. + +## Versioning & Commits (Critical for Releases) +The release pipeline is fully automated using `semantic-release`, which strictly parses commit headers to determine the next version bump. **If commits do not match the Angular Conventional Commits specification, no release will be generated.** + +### Strict Formatting Rules: +1. **Format:** `(): ` +2. **Lowercase only:** `feat:`, `fix:`, `docs:`, `chore:`. DO NOT use uppercase (`Feat`, `Fix`, `FEAT`). +3. **Punctuation:** Always use a colon `:` and a single space after the type. DO NOT use slashes (e.g., `feat/` or `Fix/`). +4. **Pull Requests:** When submitting a PR, the **PR Title** must follow this format (e.g., `feat: implement OIDC authentication`). GitHub's "Squash and Merge" feature uses the PR Title as the final commit header. If the PR Title is `Feat/OIDC`, `semantic-release` will completely ignore the merged PR. + +### Triggers: +* `feat: ...` -> MINOR release (v1.x.0) +* `fix: ...` -> PATCH release (v1.0.x) +* `perf: ...` -> PATCH release (v1.0.x) +* Commits starting with `chore:`, `docs:`, `test:`, or `refactor:` will NOT trigger a release on their own. diff --git a/.releaserc.json b/.releaserc.json index 8a27fd0..60da251 100644 --- a/.releaserc.json +++ b/.releaserc.json @@ -3,7 +3,24 @@ "plugins": [ "@semantic-release/commit-analyzer", "@semantic-release/release-notes-generator", - "@semantic-release/npm", - "@semantic-release/github" + [ + "@semantic-release/npm", + { + "tarballDir": "release" + } + ], + [ + "@semantic-release/git", + { + "assets": ["package.json", "package-lock.json"], + "message": "chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}" + } + ], + [ + "@semantic-release/github", + { + "assets": "release/*.tgz" + } + ] ] } diff --git a/package-lock.json b/package-lock.json index e2ef94f..f7c918d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "vault": "dist/index.js" }, "devDependencies": { + "@semantic-release/git": "^10.0.1", "@types/libsodium-wrappers": "npm:@types/libsodium-wrappers-sumo@^0.7.8", "@types/node": "^25.6.0", "@vitest/coverage-v8": "^4.1.4", @@ -1470,6 +1471,39 @@ "semantic-release": ">=20.1.0" } }, + "node_modules/@semantic-release/error": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@semantic-release/error/-/error-3.0.0.tgz", + "integrity": "sha512-5hiM4Un+tpl4cKw3lV4UgzJj+SmfNIDCLLw0TepzQxz9ZGV5ixnqkzIVF+3tp0ZHgcMKE+VNGHJjEeyFG2dcSw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.17" + } + }, + "node_modules/@semantic-release/git": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/@semantic-release/git/-/git-10.0.1.tgz", + "integrity": "sha512-eWrx5KguUcU2wUPaO6sfvZI0wPafUKAMNC18aXY4EnNcrZL86dEmpNVnC9uMpGZkmZJ9EfCVJBQx4pV4EMGT1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@semantic-release/error": "^3.0.0", + "aggregate-error": "^3.0.0", + "debug": "^4.0.0", + "dir-glob": "^3.0.0", + "execa": "^5.0.0", + "lodash": "^4.17.4", + "micromatch": "^4.0.0", + "p-reduce": "^2.0.0" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "semantic-release": ">=18.0.0" + } + }, "node_modules/@semantic-release/github": { "version": "11.0.6", "resolved": "https://registry.npmjs.org/@semantic-release/github/-/github-11.0.6.tgz", @@ -2647,6 +2681,20 @@ "node": ">= 14" } }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/ansi-escapes": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", @@ -2825,6 +2873,16 @@ "node": ">=10" } }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/cli-highlight": { "version": "2.1.11", "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-2.1.11.tgz", @@ -3476,6 +3534,30 @@ "@types/estree": "^1.0.0" } }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/expect-type": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", @@ -3854,6 +3936,16 @@ "node": ">= 14" } }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -3906,6 +3998,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/index-to-position": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", @@ -4000,6 +4102,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-unicode-supported": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", @@ -4496,6 +4611,13 @@ "node": ">=4" } }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/lodash-es": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.18.1.tgz", @@ -4699,6 +4821,16 @@ "node": ">=16" } }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -4979,6 +5111,19 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/npm/node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, @@ -7360,6 +7505,22 @@ ], "license": "MIT" }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-each-series": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-3.0.0.tgz", @@ -7454,6 +7615,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-reduce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-2.1.0.tgz", + "integrity": "sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/p-timeout": { "version": "6.1.4", "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-6.1.4.tgz", @@ -8185,6 +8356,13 @@ "dev": true, "license": "ISC" }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true, + "license": "ISC" + }, "node_modules/signale": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/signale/-/signale-1.4.0.tgz", @@ -8466,6 +8644,16 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", diff --git a/package.json b/package.json index d1f8a4e..d659f5c 100644 --- a/package.json +++ b/package.json @@ -9,11 +9,14 @@ "files": [ "dist", "src/core/bridge.swift", + "scripts/setup.sh", "vault.entitlements" ], "scripts": { "test": "vitest run", "build": "tsc", + "prepare": "npm run build", + "postinstall": "node -e \"if (process.platform === 'darwin') console.log('\\x1b[35m◈ Run \\'npm run setup\\' to enable biometric authentication for Vault CLI\\x1b[0m')\"", "setup": "bash scripts/setup.sh" }, "repository": { @@ -23,6 +26,9 @@ "keywords": [], "author": "Lutfi Garzon", "license": "Apache-2.0", + "publishConfig": { + "access": "public" + }, "type": "module", "bugs": { "url": "https://github.com/LutfiGarzon/vault/issues" @@ -38,6 +44,7 @@ "libsodium-wrappers-sumo": "^0.8.3" }, "devDependencies": { + "@semantic-release/git": "^10.0.1", "@types/libsodium-wrappers": "npm:@types/libsodium-wrappers-sumo@^0.7.8", "@types/node": "^25.6.0", "@vitest/coverage-v8": "^4.1.4", diff --git a/src/cli.ts b/src/cli.ts index fc953a3..6bc8537 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -1,4 +1,7 @@ import { Command } from 'commander'; +import { readFileSync } from 'node:fs'; +import { join, dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; import { initCommand } from './features/init/init.js'; import { shareCommand } from './features/share/share.js'; import { ingestCommand } from './features/ingest/ingest.js'; @@ -14,12 +17,14 @@ import { syncCommand } from './features/sync/index.js'; import { runVault } from './core/run.js'; export function runCli() { + const __dirname = dirname(fileURLToPath(import.meta.url)); + const pkg = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf8')); const program = new Command(); program .name('vault') .description('Local secure storage for env variables.') - .version('1.0.0') + .version(pkg.version) .enablePositionalOptions() .option('-e, --env ', 'Target environment (e.g. prod, qa)');