@paths.design/caws-cli 3.2.4 → 3.3.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/dist/commands/diagnose.d.ts +52 -0
- package/dist/commands/diagnose.d.ts.map +1 -0
- package/dist/commands/diagnose.js +472 -0
- package/dist/commands/status.d.ts +38 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +276 -0
- package/dist/commands/templates.d.ts +74 -0
- package/dist/commands/templates.d.ts.map +1 -0
- package/dist/commands/templates.js +235 -0
- package/dist/error-handler.d.ts +27 -2
- package/dist/error-handler.d.ts.map +1 -1
- package/dist/error-handler.js +187 -16
- package/dist/generators/jest-config.d.ts +32 -0
- package/dist/generators/jest-config.d.ts.map +1 -0
- package/dist/generators/jest-config.js +242 -0
- package/dist/index-new.d.ts +5 -0
- package/dist/index-new.d.ts.map +1 -0
- package/dist/index-new.js +317 -0
- package/dist/index.js +174 -4
- package/dist/index.js.backup +4711 -0
- package/dist/scaffold/index.d.ts.map +1 -1
- package/dist/scaffold/index.js +13 -0
- package/dist/utils/typescript-detector.d.ts +32 -0
- package/dist/utils/typescript-detector.d.ts.map +1 -0
- package/dist/utils/typescript-detector.js +185 -0
- package/package.json +4 -4
- package/templates/OIDC_SETUP.md +300 -0
- package/templates/agents.md +912 -686
- package/templates/apps/tools/caws/prompt-lint.js.backup +274 -0
- package/templates/apps/tools/caws/provenance.js.backup +73 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AAkKA;;;GAGG;AACH,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/scaffold/index.js"],"names":[],"mappings":"AAkKA;;;GAGG;AACH,6DA0UC;AA7dD;;;;GAIG;AACH,mDAHW,MAAM;;;GA8HhB;AAMD;;;GAGG;AACH,yDAGC"}
|
package/dist/scaffold/index.js
CHANGED
|
@@ -320,6 +320,19 @@ async function scaffoldProject(options) {
|
|
|
320
320
|
});
|
|
321
321
|
}
|
|
322
322
|
|
|
323
|
+
// Add AGENTS.md guide for agent workflow instructions
|
|
324
|
+
if (
|
|
325
|
+
!fs.existsSync(path.join(currentDir, 'agents.md')) &&
|
|
326
|
+
!fs.existsSync(path.join(currentDir, 'AGENTS.md')) &&
|
|
327
|
+
!fs.existsSync(path.join(currentDir, 'caws.md'))
|
|
328
|
+
) {
|
|
329
|
+
enhancements.push({
|
|
330
|
+
name: 'agents.md',
|
|
331
|
+
description: 'CAWS agent workflow guide',
|
|
332
|
+
required: false,
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
|
|
323
336
|
// Add OIDC setup guide if requested or not minimal
|
|
324
337
|
if (
|
|
325
338
|
(options.withOidc || (!options.minimal && !options.withOidc)) &&
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Detect if project is using TypeScript
|
|
3
|
+
* @param {string} projectDir - Project directory path
|
|
4
|
+
* @returns {Object} TypeScript detection result
|
|
5
|
+
*/
|
|
6
|
+
export function detectTypeScript(projectDir?: string): any;
|
|
7
|
+
/**
|
|
8
|
+
* Detect testing framework in use
|
|
9
|
+
* @param {string} projectDir - Project directory path
|
|
10
|
+
* @param {Object} packageJson - Parsed package.json (optional)
|
|
11
|
+
* @returns {Object} Testing framework detection result
|
|
12
|
+
*/
|
|
13
|
+
export function detectTestFramework(projectDir?: string, packageJson?: any): any;
|
|
14
|
+
/**
|
|
15
|
+
* Check if TypeScript project needs test configuration
|
|
16
|
+
* @param {string} projectDir - Project directory path
|
|
17
|
+
* @returns {Object} Configuration status
|
|
18
|
+
*/
|
|
19
|
+
export function checkTypeScriptTestConfig(projectDir?: string): any;
|
|
20
|
+
/**
|
|
21
|
+
* Generate configuration recommendations
|
|
22
|
+
* @param {Object} tsDetection - TypeScript detection result
|
|
23
|
+
* @param {Object} testDetection - Test framework detection result
|
|
24
|
+
* @returns {string[]} Array of recommendations
|
|
25
|
+
*/
|
|
26
|
+
export function generateRecommendations(tsDetection: any, testDetection: any): string[];
|
|
27
|
+
/**
|
|
28
|
+
* Display TypeScript detection results
|
|
29
|
+
* @param {Object} detection - Detection result from checkTypeScriptTestConfig
|
|
30
|
+
*/
|
|
31
|
+
export function displayTypeScriptDetection(detection: any): void;
|
|
32
|
+
//# sourceMappingURL=typescript-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"typescript-detector.d.ts","sourceRoot":"","sources":["../../src/utils/typescript-detector.js"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,8CAHW,MAAM,OAkChB;AAED;;;;;GAKG;AACH,iDAJW,MAAM,0BAkDhB;AAED;;;;GAIG;AACH,uDAHW,MAAM,OAiBhB;AAED;;;;;GAKG;AACH,+EAFa,MAAM,EAAE,CAuBpB;AAED;;;GAGG;AACH,iEAoBC"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview TypeScript Project Detection and Configuration
|
|
3
|
+
* Auto-detects TypeScript projects and configures testing frameworks
|
|
4
|
+
* @author @darianrosebrook
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const fs = require('fs-extra');
|
|
8
|
+
const path = require('path');
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Detect if project is using TypeScript
|
|
13
|
+
* @param {string} projectDir - Project directory path
|
|
14
|
+
* @returns {Object} TypeScript detection result
|
|
15
|
+
*/
|
|
16
|
+
function detectTypeScript(projectDir = process.cwd()) {
|
|
17
|
+
const tsconfigPath = path.join(projectDir, 'tsconfig.json');
|
|
18
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
19
|
+
|
|
20
|
+
const hasTsConfig = fs.existsSync(tsconfigPath);
|
|
21
|
+
|
|
22
|
+
let hasTypeScriptDep = false;
|
|
23
|
+
let packageJson = null;
|
|
24
|
+
|
|
25
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
26
|
+
try {
|
|
27
|
+
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
28
|
+
const allDeps = {
|
|
29
|
+
...packageJson.dependencies,
|
|
30
|
+
...packageJson.devDependencies,
|
|
31
|
+
};
|
|
32
|
+
hasTypeScriptDep = 'typescript' in allDeps;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
// Ignore parse errors
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const isTypeScript = hasTsConfig || hasTypeScriptDep;
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
isTypeScript,
|
|
42
|
+
hasTsConfig,
|
|
43
|
+
hasTypeScriptDep,
|
|
44
|
+
packageJson,
|
|
45
|
+
tsconfigPath: hasTsConfig ? tsconfigPath : null,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Detect testing framework in use
|
|
51
|
+
* @param {string} projectDir - Project directory path
|
|
52
|
+
* @param {Object} packageJson - Parsed package.json (optional)
|
|
53
|
+
* @returns {Object} Testing framework detection result
|
|
54
|
+
*/
|
|
55
|
+
function detectTestFramework(projectDir = process.cwd(), packageJson = null) {
|
|
56
|
+
if (!packageJson) {
|
|
57
|
+
const packageJsonPath = path.join(projectDir, 'package.json');
|
|
58
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
59
|
+
packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const hasJestConfig =
|
|
64
|
+
fs.existsSync(path.join(projectDir, 'jest.config.js')) ||
|
|
65
|
+
fs.existsSync(path.join(projectDir, 'jest.config.ts')) ||
|
|
66
|
+
fs.existsSync(path.join(projectDir, 'jest.config.json')) ||
|
|
67
|
+
packageJson?.jest;
|
|
68
|
+
|
|
69
|
+
const hasVitestConfig =
|
|
70
|
+
fs.existsSync(path.join(projectDir, 'vitest.config.js')) ||
|
|
71
|
+
fs.existsSync(path.join(projectDir, 'vitest.config.ts'));
|
|
72
|
+
|
|
73
|
+
const allDeps = {
|
|
74
|
+
...packageJson?.dependencies,
|
|
75
|
+
...packageJson?.devDependencies,
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const hasJestDep = 'jest' in allDeps || '@types/jest' in allDeps;
|
|
79
|
+
const hasVitestDep = 'vitest' in allDeps;
|
|
80
|
+
const hasTsJest = 'ts-jest' in allDeps;
|
|
81
|
+
|
|
82
|
+
let framework = 'none';
|
|
83
|
+
let isConfigured = false;
|
|
84
|
+
|
|
85
|
+
if (hasJestConfig || hasJestDep) {
|
|
86
|
+
framework = 'jest';
|
|
87
|
+
isConfigured = hasJestConfig;
|
|
88
|
+
} else if (hasVitestConfig || hasVitestDep) {
|
|
89
|
+
framework = 'vitest';
|
|
90
|
+
isConfigured = hasVitestConfig;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return {
|
|
94
|
+
framework,
|
|
95
|
+
isConfigured,
|
|
96
|
+
hasJest: hasJestDep,
|
|
97
|
+
hasVitest: hasVitestDep,
|
|
98
|
+
hasTsJest,
|
|
99
|
+
needsTypeScriptConfig: false, // Will be set by checkTypeScriptTestConfig
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if TypeScript project needs test configuration
|
|
105
|
+
* @param {string} projectDir - Project directory path
|
|
106
|
+
* @returns {Object} Configuration status
|
|
107
|
+
*/
|
|
108
|
+
function checkTypeScriptTestConfig(projectDir = process.cwd()) {
|
|
109
|
+
const tsDetection = detectTypeScript(projectDir);
|
|
110
|
+
const testDetection = detectTestFramework(projectDir, tsDetection.packageJson);
|
|
111
|
+
|
|
112
|
+
const needsConfig =
|
|
113
|
+
tsDetection.isTypeScript && testDetection.framework === 'jest' && !testDetection.hasTsJest;
|
|
114
|
+
|
|
115
|
+
return {
|
|
116
|
+
...tsDetection,
|
|
117
|
+
testFramework: testDetection,
|
|
118
|
+
needsJestConfig: tsDetection.isTypeScript && !testDetection.isConfigured,
|
|
119
|
+
needsTsJest: needsConfig,
|
|
120
|
+
recommendations: generateRecommendations(tsDetection, testDetection),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Generate configuration recommendations
|
|
126
|
+
* @param {Object} tsDetection - TypeScript detection result
|
|
127
|
+
* @param {Object} testDetection - Test framework detection result
|
|
128
|
+
* @returns {string[]} Array of recommendations
|
|
129
|
+
*/
|
|
130
|
+
function generateRecommendations(tsDetection, testDetection) {
|
|
131
|
+
const recommendations = [];
|
|
132
|
+
|
|
133
|
+
if (tsDetection.isTypeScript && testDetection.framework === 'none') {
|
|
134
|
+
recommendations.push('No testing framework detected');
|
|
135
|
+
recommendations.push('Recommended: Install Jest with ts-jest');
|
|
136
|
+
recommendations.push('Run: npm install --save-dev jest @types/jest ts-jest');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (tsDetection.isTypeScript && testDetection.framework === 'jest' && !testDetection.hasTsJest) {
|
|
140
|
+
recommendations.push('Jest detected but missing TypeScript support');
|
|
141
|
+
recommendations.push('Install ts-jest: npm install --save-dev ts-jest');
|
|
142
|
+
recommendations.push('Or run: caws diagnose to auto-configure');
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (tsDetection.isTypeScript && !testDetection.isConfigured) {
|
|
146
|
+
recommendations.push('Testing framework not configured');
|
|
147
|
+
recommendations.push('Run: caws scaffold to add test configuration');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return recommendations;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Display TypeScript detection results
|
|
155
|
+
* @param {Object} detection - Detection result from checkTypeScriptTestConfig
|
|
156
|
+
*/
|
|
157
|
+
function displayTypeScriptDetection(detection) {
|
|
158
|
+
if (!detection.isTypeScript) {
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
console.log(chalk.cyan('\n📦 TypeScript Project Detected'));
|
|
163
|
+
console.log(chalk.gray(` tsconfig.json: ${detection.hasTsConfig ? '✅' : '❌'}`));
|
|
164
|
+
console.log(chalk.gray(` typescript dependency: ${detection.hasTypeScriptDep ? '✅' : '❌'}`));
|
|
165
|
+
|
|
166
|
+
if (detection.testFramework.framework !== 'none') {
|
|
167
|
+
console.log(chalk.gray(` Test framework: ${detection.testFramework.framework}`));
|
|
168
|
+
console.log(chalk.gray(` Configured: ${detection.testFramework.isConfigured ? '✅' : '❌'}`));
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
if (detection.recommendations.length > 0) {
|
|
172
|
+
console.log(chalk.yellow('\n💡 Recommendations:'));
|
|
173
|
+
detection.recommendations.forEach((rec) => {
|
|
174
|
+
console.log(chalk.yellow(` ${rec}`));
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
module.exports = {
|
|
180
|
+
detectTypeScript,
|
|
181
|
+
detectTestFramework,
|
|
182
|
+
checkTypeScriptTestConfig,
|
|
183
|
+
generateRecommendations,
|
|
184
|
+
displayTypeScriptDetection,
|
|
185
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@paths.design/caws-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.3.1",
|
|
4
4
|
"description": "CAWS CLI - Coding Agent Workflow System command line tools",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -52,9 +52,11 @@
|
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
54
|
"ajv": "^8.12.0",
|
|
55
|
+
"chalk": "4.1.2",
|
|
55
56
|
"commander": "^11.0.0",
|
|
56
57
|
"fs-extra": "^11.0.0",
|
|
57
|
-
"inquirer": "8.2.7"
|
|
58
|
+
"inquirer": "8.2.7",
|
|
59
|
+
"js-yaml": "4.1.0"
|
|
58
60
|
},
|
|
59
61
|
"devDependencies": {
|
|
60
62
|
"@eslint/js": "^9.0.0",
|
|
@@ -66,10 +68,8 @@
|
|
|
66
68
|
"@types/inquirer": "^8.2.6",
|
|
67
69
|
"@types/js-yaml": "^4.0.0",
|
|
68
70
|
"@types/node": "^20.0.0",
|
|
69
|
-
"chalk": "4.1.2",
|
|
70
71
|
"eslint": "^9.0.0",
|
|
71
72
|
"jest": "30.1.3",
|
|
72
|
-
"js-yaml": "4.1.0",
|
|
73
73
|
"lint-staged": "15.5.2",
|
|
74
74
|
"prettier": "^3.0.0",
|
|
75
75
|
"semantic-release": "25.0.0-beta.6",
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# OIDC Trusted Publisher Setup
|
|
2
|
+
|
|
3
|
+
This guide helps you set up OIDC (OpenID Connect) trusted publisher for automated publishing to package registries.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
OIDC trusted publisher allows you to publish packages without storing long-lived tokens or passwords in your CI/CD environment. Instead, it uses short-lived tokens issued by the OIDC provider.
|
|
8
|
+
|
|
9
|
+
## Supported Registries
|
|
10
|
+
|
|
11
|
+
- **npm**: npm Registry
|
|
12
|
+
- **PyPI**: Python Package Index
|
|
13
|
+
- **Maven Central**: Java packages
|
|
14
|
+
- **NuGet**: .NET packages
|
|
15
|
+
|
|
16
|
+
## Setup Process
|
|
17
|
+
|
|
18
|
+
### 1. Configure OIDC Provider
|
|
19
|
+
|
|
20
|
+
Most CI/CD platforms (GitHub Actions, GitLab CI, etc.) provide built-in OIDC support.
|
|
21
|
+
|
|
22
|
+
**GitHub Actions Example:**
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
# .github/workflows/publish.yml
|
|
26
|
+
name: Publish Package
|
|
27
|
+
|
|
28
|
+
on:
|
|
29
|
+
release:
|
|
30
|
+
types: [published]
|
|
31
|
+
|
|
32
|
+
jobs:
|
|
33
|
+
publish:
|
|
34
|
+
runs-on: ubuntu-latest
|
|
35
|
+
permissions:
|
|
36
|
+
contents: read
|
|
37
|
+
id-token: write
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
- name: Setup Node.js
|
|
41
|
+
uses: actions/setup-node@v4
|
|
42
|
+
with:
|
|
43
|
+
node-version: '20'
|
|
44
|
+
registry-url: 'https://registry.npmjs.org'
|
|
45
|
+
- name: Install dependencies
|
|
46
|
+
run: npm ci
|
|
47
|
+
- name: Build package
|
|
48
|
+
run: npm run build
|
|
49
|
+
- name: Publish to npm
|
|
50
|
+
run: npm publish
|
|
51
|
+
env:
|
|
52
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### 2. Registry Configuration
|
|
56
|
+
|
|
57
|
+
#### npm Registry
|
|
58
|
+
|
|
59
|
+
1. **Create OIDC Integration**:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Using npm CLI
|
|
63
|
+
npm profile enable-2fa auth-and-writes
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
2. **Configure Trusted Publisher**:
|
|
67
|
+
- Go to npmjs.com → Account Settings → Access Tokens
|
|
68
|
+
- Create "Automation" token
|
|
69
|
+
- Configure OIDC integration
|
|
70
|
+
|
|
71
|
+
3. **Repository Settings**:
|
|
72
|
+
```json
|
|
73
|
+
// package.json
|
|
74
|
+
{
|
|
75
|
+
"publishConfig": {
|
|
76
|
+
"registry": "https://registry.npmjs.org/"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
#### PyPI (Python)
|
|
82
|
+
|
|
83
|
+
1. **Create API Token**:
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
# Using twine
|
|
87
|
+
twine upload --config-file ~/.pypirc dist/*
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
2. **OIDC Configuration**:
|
|
91
|
+
```yaml
|
|
92
|
+
# .github/workflows/publish.yml
|
|
93
|
+
- name: Publish to PyPI
|
|
94
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
95
|
+
with:
|
|
96
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Security Best Practices
|
|
100
|
+
|
|
101
|
+
#### Token Management
|
|
102
|
+
|
|
103
|
+
- ✅ **Use short-lived tokens** (1-6 hours)
|
|
104
|
+
- ✅ **Scope tokens to specific repositories**
|
|
105
|
+
- ✅ **Rotate tokens regularly**
|
|
106
|
+
- ❌ **Never store long-lived tokens in code**
|
|
107
|
+
- ❌ **Never commit tokens to version control**
|
|
108
|
+
|
|
109
|
+
#### Environment Variables
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Good: Short-lived, scoped token
|
|
113
|
+
NODE_AUTH_TOKEN=gho_shortlivedtoken123
|
|
114
|
+
|
|
115
|
+
# Bad: Long-lived, broad token
|
|
116
|
+
NPM_TOKEN=longlivedbroadtoken456
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
#### Repository Secrets
|
|
120
|
+
|
|
121
|
+
Store sensitive tokens in repository secrets:
|
|
122
|
+
|
|
123
|
+
**GitHub**: Settings → Secrets and variables → Actions
|
|
124
|
+
**GitLab**: Settings → CI/CD → Variables
|
|
125
|
+
**Azure DevOps**: Pipelines → Library → Variable groups
|
|
126
|
+
|
|
127
|
+
### 4. Testing the Setup
|
|
128
|
+
|
|
129
|
+
#### Local Testing
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# Test with dry run
|
|
133
|
+
npm publish --dry-run
|
|
134
|
+
|
|
135
|
+
# Test with local registry
|
|
136
|
+
npm publish --registry http://localhost:4873
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### CI/CD Testing
|
|
140
|
+
|
|
141
|
+
```yaml
|
|
142
|
+
# Add to your workflow for testing
|
|
143
|
+
- name: Test publish (dry run)
|
|
144
|
+
run: npm publish --dry-run
|
|
145
|
+
env:
|
|
146
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### 5. Troubleshooting
|
|
150
|
+
|
|
151
|
+
#### Common Issues
|
|
152
|
+
|
|
153
|
+
**Token Expired**:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
npm ERR! code E401
|
|
157
|
+
npm ERR! Unable to authenticate, need: Basic
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
**Solution**: Check token expiration and refresh if needed.
|
|
161
|
+
|
|
162
|
+
**Insufficient Permissions**:
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
npm ERR! code E403
|
|
166
|
+
npm ERR! Forbidden
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
**Solution**: Verify token has publish permissions for the package.
|
|
170
|
+
|
|
171
|
+
**OIDC Provider Issues**:
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
Error: Failed to get OIDC token
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
**Solution**: Check OIDC provider configuration and permissions.
|
|
178
|
+
|
|
179
|
+
#### Debug Mode
|
|
180
|
+
|
|
181
|
+
Enable debug logging:
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
# npm
|
|
185
|
+
npm config set loglevel verbose
|
|
186
|
+
|
|
187
|
+
# Python
|
|
188
|
+
export TWINE_VERBOSE=1
|
|
189
|
+
|
|
190
|
+
# Maven
|
|
191
|
+
mvn deploy -X
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### 6. Migration from Legacy Tokens
|
|
195
|
+
|
|
196
|
+
If you're migrating from username/password or long-lived tokens:
|
|
197
|
+
|
|
198
|
+
1. **Audit existing tokens**:
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
# npm
|
|
202
|
+
npm profile get
|
|
203
|
+
|
|
204
|
+
# List all tokens
|
|
205
|
+
npm token list
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
2. **Revoke old tokens**:
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
npm token delete <token-id>
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
3. **Update CI/CD workflows**:
|
|
215
|
+
- Replace `NPM_TOKEN` with `NODE_AUTH_TOKEN`
|
|
216
|
+
- Add OIDC permissions
|
|
217
|
+
- Test in staging environment
|
|
218
|
+
|
|
219
|
+
### 7. Monitoring and Alerts
|
|
220
|
+
|
|
221
|
+
Set up monitoring for:
|
|
222
|
+
|
|
223
|
+
- **Publish failures**: Alert on failed deployments
|
|
224
|
+
- **Token expiration**: Proactive token renewal
|
|
225
|
+
- **Security events**: Unusual publish patterns
|
|
226
|
+
- **Registry status**: External service health
|
|
227
|
+
|
|
228
|
+
#### Example Monitoring
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
# .github/workflows/monitor.yml
|
|
232
|
+
name: Monitor Publishing
|
|
233
|
+
|
|
234
|
+
on:
|
|
235
|
+
workflow_run:
|
|
236
|
+
workflows: ['Publish Package']
|
|
237
|
+
types: [completed]
|
|
238
|
+
|
|
239
|
+
jobs:
|
|
240
|
+
monitor:
|
|
241
|
+
runs-on: ubuntu-latest
|
|
242
|
+
steps:
|
|
243
|
+
- name: Check publish status
|
|
244
|
+
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
|
245
|
+
run: |
|
|
246
|
+
echo "Publish failed! Check logs."
|
|
247
|
+
# Send alert to Slack/Teams/etc.
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## CAWS Integration
|
|
251
|
+
|
|
252
|
+
For CAWS projects, OIDC setup integrates with:
|
|
253
|
+
|
|
254
|
+
- **Provenance tracking**: Automatic attestation of published packages
|
|
255
|
+
- **Security scanning**: Validation of published artifacts
|
|
256
|
+
- **Quality gates**: Ensure packages meet standards before publish
|
|
257
|
+
|
|
258
|
+
### CAWS-Specific Configuration
|
|
259
|
+
|
|
260
|
+
```yaml
|
|
261
|
+
# .caws/working-spec.yaml
|
|
262
|
+
non_functional:
|
|
263
|
+
security:
|
|
264
|
+
- 'oidc-authentication'
|
|
265
|
+
- 'token-rotation'
|
|
266
|
+
- 'publish-attestation'
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Automated Provenance
|
|
270
|
+
|
|
271
|
+
CAWS automatically generates provenance information:
|
|
272
|
+
|
|
273
|
+
```bash
|
|
274
|
+
# Generate SBOM and attestation
|
|
275
|
+
caws attest --format=slsa
|
|
276
|
+
|
|
277
|
+
# Validate before publish
|
|
278
|
+
caws validate --security-scan
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
## Resources
|
|
282
|
+
|
|
283
|
+
- [npm OIDC Documentation](https://docs.npmjs.com/about-access-tokens)
|
|
284
|
+
- [GitHub Actions OIDC](https://docs.github.com/en/actions/deployment/security/hardening-your-deployments/about-security-hardening-with-openid-connect)
|
|
285
|
+
- [PyPI Trusted Publishing](https://docs.pypi.org/trusted-publishing/)
|
|
286
|
+
- [OIDC Specification](https://openid.net/connect/)
|
|
287
|
+
|
|
288
|
+
## Support
|
|
289
|
+
|
|
290
|
+
For issues with OIDC setup:
|
|
291
|
+
|
|
292
|
+
1. Check the troubleshooting section above
|
|
293
|
+
2. Review registry-specific documentation
|
|
294
|
+
3. Open an issue in the CAWS repository
|
|
295
|
+
4. Contact your organization's security team
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
**Note**: This guide provides general OIDC setup instructions. Always follow your organization's specific security policies and procedures.
|
|
300
|
+
|