@northbridge-security/secureai 0.1.13
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/.claude/README.md +122 -0
- package/.claude/commands/architect/clean.md +978 -0
- package/.claude/commands/architect/kiss.md +762 -0
- package/.claude/commands/architect/review.md +704 -0
- package/.claude/commands/catchup.md +90 -0
- package/.claude/commands/code.md +115 -0
- package/.claude/commands/commit.md +1218 -0
- package/.claude/commands/cover.md +1298 -0
- package/.claude/commands/fmea.md +275 -0
- package/.claude/commands/kaizen.md +312 -0
- package/.claude/commands/pr.md +503 -0
- package/.claude/commands/todo.md +99 -0
- package/.claude/commands/worktree.md +738 -0
- package/.claude/commands/wrapup.md +103 -0
- package/LICENSE +183 -0
- package/README.md +108 -0
- package/dist/cli.js +75634 -0
- package/docs/agents/devops-reviewer.md +889 -0
- package/docs/agents/kiss-simplifier.md +1088 -0
- package/docs/agents/typescript.md +8 -0
- package/docs/guides/README.md +109 -0
- package/docs/guides/agents.clean.arch.md +244 -0
- package/docs/guides/agents.clean.arch.ts.md +1314 -0
- package/docs/guides/agents.gotask.md +1037 -0
- package/docs/guides/agents.markdown.md +1209 -0
- package/docs/guides/agents.onepassword.md +285 -0
- package/docs/guides/agents.sonar.md +857 -0
- package/docs/guides/agents.tdd.md +838 -0
- package/docs/guides/agents.tdd.ts.md +1062 -0
- package/docs/guides/agents.typesript.md +1389 -0
- package/docs/guides/github-mcp.md +1075 -0
- package/package.json +130 -0
- package/packages/secureai-cli/src/cli.ts +21 -0
- package/tasks/README.md +880 -0
- package/tasks/aws.yml +64 -0
- package/tasks/bash.yml +118 -0
- package/tasks/bun.yml +738 -0
- package/tasks/claude.yml +183 -0
- package/tasks/docker.yml +420 -0
- package/tasks/docs.yml +127 -0
- package/tasks/git.yml +1336 -0
- package/tasks/gotask.yml +132 -0
- package/tasks/json.yml +77 -0
- package/tasks/markdown.yml +95 -0
- package/tasks/onepassword.yml +350 -0
- package/tasks/security.yml +102 -0
- package/tasks/sonar.yml +437 -0
- package/tasks/template.yml +74 -0
- package/tasks/vscode.yml +103 -0
- package/tasks/yaml.yml +121 -0
package/tasks/gotask.yml
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
# GoTask Development Utilities
|
|
2
|
+
# Tools and cookie cutters for coding, testing, and maintaining task files
|
|
3
|
+
|
|
4
|
+
version: "3"
|
|
5
|
+
|
|
6
|
+
tasks:
|
|
7
|
+
default:
|
|
8
|
+
desc: "Show available GoTask utilities"
|
|
9
|
+
aliases: [help, h]
|
|
10
|
+
silent: true
|
|
11
|
+
cmds:
|
|
12
|
+
- |
|
|
13
|
+
# Color codes
|
|
14
|
+
GREEN='\033[0;32m'
|
|
15
|
+
YELLOW='\033[0;33m'
|
|
16
|
+
BOLD='\033[1m'
|
|
17
|
+
NC='\033[0m'
|
|
18
|
+
|
|
19
|
+
echo -e "${BOLD}GoTask Development Utilities${NC}"
|
|
20
|
+
echo ""
|
|
21
|
+
echo "Command Alias Description Examples"
|
|
22
|
+
echo "───────────────────────────────────────────────────────────────────────────────────────────────────"
|
|
23
|
+
echo -e "${BOLD}Task Development:${NC}"
|
|
24
|
+
echo -e " ${GREEN}task gotask:format${NC} ${YELLOW}f${NC} Format default task in Taskfile"
|
|
25
|
+
echo -e " ${GREEN}task gotask:new:task${NC} ${YELLOW}nt${NC} Create new task in Taskfile.yml"
|
|
26
|
+
echo -e " ${GREEN}task gotask:new:script${NC} ${YELLOW}ns${NC} Create new TypeScript task script"
|
|
27
|
+
echo -e " ${GREEN}task gotask:validate${NC} ${YELLOW}v${NC} Validate all Taskfile.yml syntax"
|
|
28
|
+
echo -e " ${GREEN}task gotask:deps:check${NC} ${YELLOW}dc${NC} Check for missing task dependencies"
|
|
29
|
+
echo ""
|
|
30
|
+
echo -e "${BOLD}Setup & Configuration:${NC}"
|
|
31
|
+
echo -e " ${GREEN}task gotask:setup:extensions${NC} ${YELLOW}se${NC} Install recommended VSCode extensions"
|
|
32
|
+
echo ""
|
|
33
|
+
echo -e "${BOLD}Documentation:${NC}"
|
|
34
|
+
echo -e " ${GREEN}task gotask:docs:generate${NC} ${YELLOW}dg${NC} Generate task documentation"
|
|
35
|
+
echo -e " ${GREEN}task gotask:docs:view${NC} ${YELLOW}dv${NC} View best practices guide"
|
|
36
|
+
echo -e " ${GREEN}task gotask:docs:edit${NC} ${YELLOW}de${NC} Edit best practices guide"
|
|
37
|
+
echo ""
|
|
38
|
+
echo -e "${BOLD}Templates:${NC}"
|
|
39
|
+
echo -e " ${GREEN}task gotask:template:basic${NC} ${YELLOW}tb${NC} Generate basic task template"
|
|
40
|
+
echo -e " ${GREEN}task gotask:template:build${NC} ${YELLOW}tbu${NC} Generate build task template"
|
|
41
|
+
echo -e " ${GREEN}task gotask:template:test${NC} ${YELLOW}tt${NC} Generate test task template"
|
|
42
|
+
|
|
43
|
+
format:
|
|
44
|
+
desc: Format default task in Taskfile
|
|
45
|
+
aliases: [f]
|
|
46
|
+
silent: true
|
|
47
|
+
cmds:
|
|
48
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/format-default.ts {{.CLI_ARGS}}
|
|
49
|
+
|
|
50
|
+
new:task:
|
|
51
|
+
desc: Create a new task in Taskfile.yml
|
|
52
|
+
aliases: [nt]
|
|
53
|
+
silent: true
|
|
54
|
+
cmds:
|
|
55
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/new-task.ts {{.CLI_ARGS}}
|
|
56
|
+
|
|
57
|
+
new:script:
|
|
58
|
+
desc: Create a new TypeScript task script
|
|
59
|
+
aliases: [ns]
|
|
60
|
+
silent: true
|
|
61
|
+
cmds:
|
|
62
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/new-script.ts {{.CLI_ARGS}}
|
|
63
|
+
|
|
64
|
+
validate:
|
|
65
|
+
desc: Validate all Taskfile.yml syntax
|
|
66
|
+
aliases: [v]
|
|
67
|
+
silent: true
|
|
68
|
+
cmds:
|
|
69
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/validate-taskfiles.ts
|
|
70
|
+
|
|
71
|
+
deps:check:
|
|
72
|
+
desc: Check for missing task dependencies
|
|
73
|
+
aliases: [dc]
|
|
74
|
+
silent: true
|
|
75
|
+
cmds:
|
|
76
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/check-deps.ts
|
|
77
|
+
|
|
78
|
+
setup:extensions:
|
|
79
|
+
desc: Install recommended VSCode/Cursor extensions
|
|
80
|
+
aliases: [se]
|
|
81
|
+
silent: true
|
|
82
|
+
cmds:
|
|
83
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/setup-vscode-extensions.ts
|
|
84
|
+
|
|
85
|
+
docs:generate:
|
|
86
|
+
desc: Generate task documentation
|
|
87
|
+
aliases: [dg]
|
|
88
|
+
silent: true
|
|
89
|
+
cmds:
|
|
90
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/generate-docs.ts
|
|
91
|
+
|
|
92
|
+
docs:view:
|
|
93
|
+
desc: View gotask best practices guide
|
|
94
|
+
aliases: [dv]
|
|
95
|
+
silent: true
|
|
96
|
+
cmds:
|
|
97
|
+
- |
|
|
98
|
+
if command -v bat &> /dev/null; then
|
|
99
|
+
bat src/tasks/gotask/docs/best-practices.md
|
|
100
|
+
elif command -v less &> /dev/null; then
|
|
101
|
+
less src/tasks/gotask/docs/best-practices.md
|
|
102
|
+
else
|
|
103
|
+
cat src/tasks/gotask/docs/best-practices.md
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
docs:edit:
|
|
107
|
+
desc: Edit gotask best practices guide
|
|
108
|
+
aliases: [de]
|
|
109
|
+
silent: true
|
|
110
|
+
cmds:
|
|
111
|
+
- ${EDITOR:-code} src/tasks/gotask/docs/best-practices.md
|
|
112
|
+
|
|
113
|
+
template:basic:
|
|
114
|
+
desc: Generate basic task template
|
|
115
|
+
aliases: [tb]
|
|
116
|
+
silent: true
|
|
117
|
+
cmds:
|
|
118
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/templates/basic.ts {{.CLI_ARGS}}
|
|
119
|
+
|
|
120
|
+
template:build:
|
|
121
|
+
desc: Generate build task template
|
|
122
|
+
aliases: [tbu]
|
|
123
|
+
silent: true
|
|
124
|
+
cmds:
|
|
125
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/templates/build.ts {{.CLI_ARGS}}
|
|
126
|
+
|
|
127
|
+
template:test:
|
|
128
|
+
desc: Generate test task template
|
|
129
|
+
aliases: [tt]
|
|
130
|
+
silent: true
|
|
131
|
+
cmds:
|
|
132
|
+
- bun run {{.TASKFILE_DIR}}/../src/tasks/gotask/templates/test.ts {{.CLI_ARGS}}
|
package/tasks/json.yml
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# JSON Linting, Parsing & Validation Tasks
|
|
2
|
+
# Provides JSON linting, parsing, schema validation and common operations
|
|
3
|
+
|
|
4
|
+
version: "3"
|
|
5
|
+
|
|
6
|
+
vars:
|
|
7
|
+
DEFAULT_PATTERNS: "*.json,**/*.json,!node_modules/**,!dist/**,!.taskmaster/**"
|
|
8
|
+
|
|
9
|
+
tasks:
|
|
10
|
+
default:
|
|
11
|
+
desc: "Show available JSON tasks"
|
|
12
|
+
aliases: [help, h]
|
|
13
|
+
silent: true
|
|
14
|
+
cmds:
|
|
15
|
+
- |
|
|
16
|
+
# Color codes
|
|
17
|
+
GREEN='\033[0;32m'
|
|
18
|
+
YELLOW='\033[0;33m'
|
|
19
|
+
BOLD='\033[1m'
|
|
20
|
+
NC='\033[0m'
|
|
21
|
+
|
|
22
|
+
echo -e "${BOLD}JSON Linting, Parsing & Validation${NC}"
|
|
23
|
+
echo ""
|
|
24
|
+
echo "Command Alias Description Examples"
|
|
25
|
+
echo "───────────────────────────────────────────────────────────────────────────────────────────────────"
|
|
26
|
+
echo -e " ${GREEN}task json:lint${NC} ${YELLOW}l${NC} Lint JSON files FILES=\"*.json\""
|
|
27
|
+
echo -e " ${GREEN}task json:lint:fix${NC} ${YELLOW}lf${NC} Auto-fix JSON formatting FILES=\"*.json\""
|
|
28
|
+
echo ""
|
|
29
|
+
echo -e "${BOLD}Usage Examples:${NC}"
|
|
30
|
+
echo -e " task json:lint Lint all JSON files (quiet on success)"
|
|
31
|
+
echo -e " task json:lint FILES=\"*.json\" Lint specific pattern"
|
|
32
|
+
echo -e " VERBOSE=1 task json:lint Show output even on success"
|
|
33
|
+
echo -e " task json:lint:fix Auto-fix all issues"
|
|
34
|
+
|
|
35
|
+
lint:
|
|
36
|
+
desc: "Lint JSON files (quiet on success, use VERBOSE=1 for details)"
|
|
37
|
+
aliases: [l]
|
|
38
|
+
silent: true
|
|
39
|
+
vars:
|
|
40
|
+
FILE_PATTERNS: "{{.FILES | default .DEFAULT_PATTERNS}}"
|
|
41
|
+
VERBOSE_FLAG: '{{.VERBOSE | default ""}}'
|
|
42
|
+
cmds:
|
|
43
|
+
- |
|
|
44
|
+
REPO_URL=$(task git:repo:url 2>/dev/null || echo "")
|
|
45
|
+
SCRIPT="{{.TASKFILE_DIR}}/../src/tasks/json/lint.ts"
|
|
46
|
+
|
|
47
|
+
if [ "$REPO_URL" = "https://github.com/northbridge-security/ai-toolkit" ] && [ -f "$SCRIPT" ]; then
|
|
48
|
+
bun run "$SCRIPT"
|
|
49
|
+
else
|
|
50
|
+
# Fallback to ai-toolkit CLI
|
|
51
|
+
npx @northbridge-security/ai-toolkit json lint -f "$FILES"
|
|
52
|
+
fi
|
|
53
|
+
env:
|
|
54
|
+
FILES: "{{.FILE_PATTERNS}}"
|
|
55
|
+
VERBOSE: "{{.VERBOSE_FLAG}}"
|
|
56
|
+
|
|
57
|
+
lint:fix:
|
|
58
|
+
desc: "Auto-fix JSON formatting (pretty-print with 2-space indent)"
|
|
59
|
+
aliases: [lf, fix]
|
|
60
|
+
silent: true
|
|
61
|
+
vars:
|
|
62
|
+
FILE_PATTERNS: "{{.FILES | default .DEFAULT_PATTERNS}}"
|
|
63
|
+
VERBOSE_FLAG: '{{.VERBOSE | default ""}}'
|
|
64
|
+
cmds:
|
|
65
|
+
- |
|
|
66
|
+
REPO_URL=$(task git:repo:url 2>/dev/null || echo "")
|
|
67
|
+
SCRIPT="{{.TASKFILE_DIR}}/../src/tasks/json/lint-fix.ts"
|
|
68
|
+
|
|
69
|
+
if [ "$REPO_URL" = "https://github.com/northbridge-security/ai-toolkit" ] && [ -f "$SCRIPT" ]; then
|
|
70
|
+
bun run "$SCRIPT"
|
|
71
|
+
else
|
|
72
|
+
# Fallback to ai-toolkit CLI
|
|
73
|
+
npx @northbridge-security/ai-toolkit json lint --fix -f "$FILES"
|
|
74
|
+
fi
|
|
75
|
+
env:
|
|
76
|
+
FILES: "{{.FILE_PATTERNS}}"
|
|
77
|
+
VERBOSE: "{{.VERBOSE_FLAG}}"
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Markdown Linting & Validation Tasks
|
|
2
|
+
# Provides markdown validation, linting, and auto-fixing for all markdown files in the project.
|
|
3
|
+
|
|
4
|
+
version: "3"
|
|
5
|
+
|
|
6
|
+
vars:
|
|
7
|
+
DEFAULT_PATTERNS: "*.md,docs/**/*.md,.github/**/*.md,tasks/**/*.md"
|
|
8
|
+
MARKDOWNLINT_CONFIG: ".markdownlint.yaml"
|
|
9
|
+
|
|
10
|
+
tasks:
|
|
11
|
+
default:
|
|
12
|
+
desc: "Show available Markdown tasks"
|
|
13
|
+
aliases: [help, h]
|
|
14
|
+
silent: true
|
|
15
|
+
cmds:
|
|
16
|
+
- |
|
|
17
|
+
# Color codes
|
|
18
|
+
GREEN='\033[0;32m'
|
|
19
|
+
YELLOW='\033[0;33m'
|
|
20
|
+
BOLD='\033[1m'
|
|
21
|
+
NC='\033[0m'
|
|
22
|
+
|
|
23
|
+
echo -e "${BOLD}Markdown Linting & Validation${NC}"
|
|
24
|
+
echo ""
|
|
25
|
+
echo "Command Alias Description Examples"
|
|
26
|
+
echo "───────────────────────────────────────────────────────────────────────────────────────────────────"
|
|
27
|
+
echo -e " ${GREEN}task markdown:lint${NC} ${YELLOW}l${NC} Lint markdown files FILES=\"*.md\""
|
|
28
|
+
echo -e " ${GREEN}task markdown:lint:fix${NC} ${YELLOW}lf${NC} Auto-fix markdown formatting FILES=\"*.md\""
|
|
29
|
+
echo -e " ${GREEN}task markdown:setup${NC} ${YELLOW}s${NC} Install markdownlint & create config"
|
|
30
|
+
echo ""
|
|
31
|
+
echo -e "${BOLD}Usage Examples:${NC}"
|
|
32
|
+
echo -e " task markdown:lint # Lint all markdown files (quiet on success)"
|
|
33
|
+
echo -e " task markdown:lint FILES=\"*.md\" # Lint specific pattern"
|
|
34
|
+
echo -e " VERBOSE=1 task markdown:lint # Show output even on success"
|
|
35
|
+
echo -e " task markdown:lint:fix # Auto-fix all issues"
|
|
36
|
+
|
|
37
|
+
lint:
|
|
38
|
+
desc: "Lint markdown files (quiet on success, use VERBOSE=1 for details)"
|
|
39
|
+
aliases: [l]
|
|
40
|
+
silent: true
|
|
41
|
+
vars:
|
|
42
|
+
FILE_PATTERNS: "{{.FILES | default .DEFAULT_PATTERNS}}"
|
|
43
|
+
VERBOSE_FLAG: '{{.VERBOSE | default ""}}'
|
|
44
|
+
cmds:
|
|
45
|
+
- |
|
|
46
|
+
REPO_URL=$(task git:repo:url 2>/dev/null || echo "")
|
|
47
|
+
SCRIPT="{{.TASKFILE_DIR}}/../src/tasks/markdown/lint.ts"
|
|
48
|
+
|
|
49
|
+
if [ "$REPO_URL" = "https://github.com/northbridge-security/ai-toolkit" ] && [ -f "$SCRIPT" ]; then
|
|
50
|
+
bun run "$SCRIPT"
|
|
51
|
+
else
|
|
52
|
+
# Fallback to ai-toolkit CLI
|
|
53
|
+
npx @northbridge-security/ai-toolkit markdown lint -f "$FILES"
|
|
54
|
+
fi
|
|
55
|
+
env:
|
|
56
|
+
FILES: "{{.FILE_PATTERNS}}"
|
|
57
|
+
VERBOSE: "{{.VERBOSE_FLAG}}"
|
|
58
|
+
|
|
59
|
+
lint:fix:
|
|
60
|
+
desc: "Auto-fix markdown files where possible (quiet when no changes)"
|
|
61
|
+
aliases: [lf, fix]
|
|
62
|
+
silent: true
|
|
63
|
+
vars:
|
|
64
|
+
FILE_PATTERNS: "{{.FILES | default .DEFAULT_PATTERNS}}"
|
|
65
|
+
VERBOSE_FLAG: '{{.VERBOSE | default ""}}'
|
|
66
|
+
cmds:
|
|
67
|
+
- |
|
|
68
|
+
REPO_URL=$(task git:repo:url 2>/dev/null || echo "")
|
|
69
|
+
SCRIPT="{{.TASKFILE_DIR}}/../src/tasks/markdown/lint-fix.ts"
|
|
70
|
+
|
|
71
|
+
if [ "$REPO_URL" = "https://github.com/northbridge-security/ai-toolkit" ] && [ -f "$SCRIPT" ]; then
|
|
72
|
+
bun run "$SCRIPT"
|
|
73
|
+
else
|
|
74
|
+
# Fallback to ai-toolkit CLI
|
|
75
|
+
npx @northbridge-security/ai-toolkit markdown lint --fix -f "$FILES"
|
|
76
|
+
fi
|
|
77
|
+
env:
|
|
78
|
+
FILES: "{{.FILE_PATTERNS}}"
|
|
79
|
+
VERBOSE: "{{.VERBOSE_FLAG}}"
|
|
80
|
+
|
|
81
|
+
setup:
|
|
82
|
+
desc: "Install markdownlint CLI tool and create .markdownlint.yaml config"
|
|
83
|
+
aliases: [s]
|
|
84
|
+
silent: true
|
|
85
|
+
cmds:
|
|
86
|
+
- |
|
|
87
|
+
REPO_URL=$(task git:repo:url 2>/dev/null || echo "")
|
|
88
|
+
SCRIPT="{{.TASKFILE_DIR}}/../src/tasks/markdown/setup.ts"
|
|
89
|
+
|
|
90
|
+
if [ "$REPO_URL" = "https://github.com/northbridge-security/ai-toolkit" ] && [ -f "$SCRIPT" ]; then
|
|
91
|
+
bun run "$SCRIPT"
|
|
92
|
+
else
|
|
93
|
+
# Fallback to ai-toolkit CLI
|
|
94
|
+
npx @northbridge-security/ai-toolkit markdown setup
|
|
95
|
+
fi
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
version: "3"
|
|
2
|
+
|
|
3
|
+
# 1Password Secret Management Tasks
|
|
4
|
+
# Minimal set of tasks for secure secret management
|
|
5
|
+
|
|
6
|
+
tasks:
|
|
7
|
+
default:
|
|
8
|
+
desc: "Show available 1Password tasks"
|
|
9
|
+
aliases: [help]
|
|
10
|
+
silent: true
|
|
11
|
+
cmds:
|
|
12
|
+
- |
|
|
13
|
+
# Color codes
|
|
14
|
+
GREEN='\033[0;32m'
|
|
15
|
+
YELLOW='\033[0;33m'
|
|
16
|
+
RED='\033[0;31m'
|
|
17
|
+
BOLD='\033[1m'
|
|
18
|
+
NC='\033[0m'
|
|
19
|
+
|
|
20
|
+
echo -e "${BOLD}1Password Secret Management${NC}"
|
|
21
|
+
echo ""
|
|
22
|
+
echo -e "${YELLOW}ℹ️ Secrets loaded automatically by tasks that need them${NC}"
|
|
23
|
+
echo ""
|
|
24
|
+
echo "Command Alias Description Examples"
|
|
25
|
+
echo "───────────────────────────────────────────────────────────────────────────────────────────────────"
|
|
26
|
+
echo -e " ${GREEN}source \$(task op:export)${NC} ${YELLOW}op:x${NC} Load secrets into shell (interactive)"
|
|
27
|
+
echo -e " ${GREEN}source \$(task op:export:force)${NC} ${YELLOW}op:xf${NC} Force reload all secrets"
|
|
28
|
+
echo -e " ${GREEN}task op:verify${NC} ${YELLOW}op:ve${NC} Verify required secrets are loaded"
|
|
29
|
+
echo -e " ${GREEN}task op:validate${NC} ${YELLOW}op:v${NC} Validate all exported secrets"
|
|
30
|
+
echo -e " ${GREEN}task op:cleanup${NC} ${YELLOW}op:c${NC} Clean up temp secret files"
|
|
31
|
+
echo -e " ${GREEN}task op:test${NC} ${YELLOW}op:t${NC} Test GitHub token permissions"
|
|
32
|
+
|
|
33
|
+
export:
|
|
34
|
+
desc: "Export secrets to temp file - Use: source $(task op:export)"
|
|
35
|
+
aliases: [x]
|
|
36
|
+
silent: true
|
|
37
|
+
cmds:
|
|
38
|
+
- |
|
|
39
|
+
set -euo pipefail
|
|
40
|
+
|
|
41
|
+
# Get unique temp directory for this repo
|
|
42
|
+
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
43
|
+
REPO_HASH=$(echo "$REPO_PATH" | shasum -a 256 | cut -d' ' -f1 | cut -c1-12)
|
|
44
|
+
TEMP_DIR="/tmp/op-secrets-$REPO_HASH"
|
|
45
|
+
TEMP_ENV="$TEMP_DIR/.env"
|
|
46
|
+
|
|
47
|
+
# Check if already exported (idempotent)
|
|
48
|
+
if [ -f "$TEMP_ENV" ]; then
|
|
49
|
+
# Verify file is recent (< 1 hour old)
|
|
50
|
+
if [ "$(uname)" = "Darwin" ]; then
|
|
51
|
+
FILE_AGE=$(stat -f %m "$TEMP_ENV" 2>/dev/null || echo 0)
|
|
52
|
+
else
|
|
53
|
+
FILE_AGE=$(stat -c %Y "$TEMP_ENV" 2>/dev/null || echo 0)
|
|
54
|
+
fi
|
|
55
|
+
CURRENT_TIME=$(date +%s)
|
|
56
|
+
AGE_SECONDS=$((CURRENT_TIME - FILE_AGE))
|
|
57
|
+
|
|
58
|
+
if [ $AGE_SECONDS -lt 3600 ]; then
|
|
59
|
+
# File is fresh, reuse it
|
|
60
|
+
echo "$TEMP_ENV"
|
|
61
|
+
exit 0
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
|
|
65
|
+
# Check if 1Password CLI is available
|
|
66
|
+
OP_AVAILABLE=false
|
|
67
|
+
if command -v op &> /dev/null; then
|
|
68
|
+
OP_AVAILABLE=true
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
# Create secure temp directory
|
|
72
|
+
mkdir -p "$TEMP_DIR"
|
|
73
|
+
chmod 700 "$TEMP_DIR"
|
|
74
|
+
|
|
75
|
+
# Create temp file with secure permissions
|
|
76
|
+
touch "$TEMP_ENV"
|
|
77
|
+
chmod 600 "$TEMP_ENV"
|
|
78
|
+
|
|
79
|
+
# Clear file
|
|
80
|
+
: > "$TEMP_ENV"
|
|
81
|
+
|
|
82
|
+
# Track unresolved op:// references
|
|
83
|
+
UNRESOLVED_REFS=""
|
|
84
|
+
|
|
85
|
+
# Function to process an env file
|
|
86
|
+
process_env_file() {
|
|
87
|
+
local env_file="$1"
|
|
88
|
+
[ -f "$env_file" ] || return 0
|
|
89
|
+
|
|
90
|
+
while IFS='=' read -r key value || [ -n "$key" ]; do
|
|
91
|
+
# Skip comments and empty lines
|
|
92
|
+
[[ "$key" =~ ^#.*$ ]] || [[ -z "$key" ]] && continue
|
|
93
|
+
|
|
94
|
+
# Remove any existing entry for this key (allows override)
|
|
95
|
+
if [ -f "$TEMP_ENV" ]; then
|
|
96
|
+
grep -v "^export $key=" "$TEMP_ENV" > "$TEMP_ENV.tmp" 2>/dev/null || true
|
|
97
|
+
mv "$TEMP_ENV.tmp" "$TEMP_ENV" 2>/dev/null || true
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Resolve op:// references via 1Password CLI
|
|
101
|
+
if [[ "$value" =~ ^op:// ]]; then
|
|
102
|
+
if [ "$OP_AVAILABLE" = true ]; then
|
|
103
|
+
resolved=$(op read "$value" 2>/dev/null) || true
|
|
104
|
+
if [ -n "$resolved" ]; then
|
|
105
|
+
echo "export $key='$resolved'" >> "$TEMP_ENV"
|
|
106
|
+
else
|
|
107
|
+
# op available but resolution failed - track for error
|
|
108
|
+
UNRESOLVED_REFS="$UNRESOLVED_REFS\n $key=$value"
|
|
109
|
+
fi
|
|
110
|
+
else
|
|
111
|
+
# op not available - track unresolved reference
|
|
112
|
+
UNRESOLVED_REFS="$UNRESOLVED_REFS\n $key=$value"
|
|
113
|
+
fi
|
|
114
|
+
else
|
|
115
|
+
# Plain text value, export as-is
|
|
116
|
+
echo "export $key='$value'" >> "$TEMP_ENV"
|
|
117
|
+
fi
|
|
118
|
+
done < "$env_file"
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
# Process .env first, then .env.local (local overrides base)
|
|
122
|
+
process_env_file ".env"
|
|
123
|
+
process_env_file ".env.local"
|
|
124
|
+
|
|
125
|
+
# Only error if there are unresolved op:// references
|
|
126
|
+
if [ -n "$UNRESOLVED_REFS" ]; then
|
|
127
|
+
if [ "$OP_AVAILABLE" = true ]; then
|
|
128
|
+
echo "❌ Failed to resolve 1Password references:" >&2
|
|
129
|
+
else
|
|
130
|
+
echo "❌ 1Password CLI (op) not installed but op:// references found:" >&2
|
|
131
|
+
fi
|
|
132
|
+
echo -e "$UNRESOLVED_REFS" >&2
|
|
133
|
+
echo "" >&2
|
|
134
|
+
if [ "$OP_AVAILABLE" = false ]; then
|
|
135
|
+
echo "Install 1Password CLI: https://developer.1password.com/docs/cli/get-started/" >&2
|
|
136
|
+
echo "Or replace op:// references with plain values in .env.local" >&2
|
|
137
|
+
else
|
|
138
|
+
echo "Ensure 1Password is unlocked and references are valid" >&2
|
|
139
|
+
fi
|
|
140
|
+
exit 1
|
|
141
|
+
fi
|
|
142
|
+
|
|
143
|
+
# Output temp file path (for sourcing)
|
|
144
|
+
echo "$TEMP_ENV"
|
|
145
|
+
|
|
146
|
+
# Security: Auto-delete secrets file after 10 seconds
|
|
147
|
+
# This runs in background so the task returns immediately
|
|
148
|
+
# The file will be deleted even if the parent shell exits
|
|
149
|
+
(sleep 10 && rm -f "$TEMP_ENV" 2>/dev/null) &
|
|
150
|
+
disown 2>/dev/null || true
|
|
151
|
+
|
|
152
|
+
export:force:
|
|
153
|
+
desc: "Force re-export secrets - Use: source $(task op:export:force)"
|
|
154
|
+
aliases: [xf]
|
|
155
|
+
silent: true
|
|
156
|
+
cmds:
|
|
157
|
+
- |
|
|
158
|
+
# Delete existing temp file to force re-export
|
|
159
|
+
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
160
|
+
REPO_HASH=$(echo "$REPO_PATH" | shasum -a 256 | cut -d' ' -f1 | cut -c1-12)
|
|
161
|
+
rm -f "/tmp/op-secrets-$REPO_HASH/.env"
|
|
162
|
+
|
|
163
|
+
# Run normal export
|
|
164
|
+
task op:export
|
|
165
|
+
|
|
166
|
+
verify:
|
|
167
|
+
desc: "Verify required secrets are loaded (at least one AI key + required tokens)"
|
|
168
|
+
aliases: [ve]
|
|
169
|
+
silent: true
|
|
170
|
+
cmds:
|
|
171
|
+
- |
|
|
172
|
+
set -euo pipefail
|
|
173
|
+
|
|
174
|
+
# Color codes
|
|
175
|
+
RED='\033[0;31m'
|
|
176
|
+
GREEN='\033[0;32m'
|
|
177
|
+
NC='\033[0m'
|
|
178
|
+
|
|
179
|
+
failed=false
|
|
180
|
+
|
|
181
|
+
# Check at least one AI API key is set and resolved
|
|
182
|
+
ai_key_found=false
|
|
183
|
+
for key in ANTHROPIC_API_KEY PERPLEXITY_API_KEY OPENAI_API_KEY; do
|
|
184
|
+
value="${!key:-}"
|
|
185
|
+
if [ -n "$value" ] && [[ ! "$value" =~ ^op:// ]]; then
|
|
186
|
+
ai_key_found=true
|
|
187
|
+
break
|
|
188
|
+
fi
|
|
189
|
+
done
|
|
190
|
+
|
|
191
|
+
if [ "$ai_key_found" = false ]; then
|
|
192
|
+
echo -e "${RED}❌ No AI API key found${NC}" >&2
|
|
193
|
+
echo " Required: At least one of ANTHROPIC_API_KEY, PERPLEXITY_API_KEY, or OPENAI_API_KEY" >&2
|
|
194
|
+
echo " Run: source \$(task op:export)" >&2
|
|
195
|
+
failed=true
|
|
196
|
+
fi
|
|
197
|
+
|
|
198
|
+
# Check required tokens
|
|
199
|
+
for key in GITHUB_TOKEN SEMGREP_APP_TOKEN; do
|
|
200
|
+
value="${!key:-}"
|
|
201
|
+
|
|
202
|
+
if [ -z "$value" ]; then
|
|
203
|
+
echo -e "${RED}❌ $key: NOT SET${NC}" >&2
|
|
204
|
+
failed=true
|
|
205
|
+
continue
|
|
206
|
+
fi
|
|
207
|
+
|
|
208
|
+
if [[ "$value" =~ ^op:// ]]; then
|
|
209
|
+
echo -e "${RED}❌ $key: NOT RESOLVED${NC}" >&2
|
|
210
|
+
echo " Run: source \$(task op:export)" >&2
|
|
211
|
+
failed=true
|
|
212
|
+
fi
|
|
213
|
+
done
|
|
214
|
+
|
|
215
|
+
if [ "$failed" = true ]; then
|
|
216
|
+
exit 1
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
cleanup:
|
|
220
|
+
desc: "Clean up exported secrets temp file"
|
|
221
|
+
aliases: [c]
|
|
222
|
+
silent: true
|
|
223
|
+
cmds:
|
|
224
|
+
- |
|
|
225
|
+
REPO_PATH=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
226
|
+
REPO_HASH=$(echo "$REPO_PATH" | shasum -a 256 | cut -d' ' -f1 | cut -c1-12)
|
|
227
|
+
TEMP_DIR="/tmp/op-secrets-$REPO_HASH"
|
|
228
|
+
|
|
229
|
+
if [ -d "$TEMP_DIR" ]; then
|
|
230
|
+
rm -rf "$TEMP_DIR"
|
|
231
|
+
echo "✓ Cleaned up secrets temp file"
|
|
232
|
+
else
|
|
233
|
+
echo "No temp files to clean"
|
|
234
|
+
fi
|
|
235
|
+
|
|
236
|
+
validate:
|
|
237
|
+
desc: "Validate exported environment variables (idempotent, silent if valid)"
|
|
238
|
+
aliases: [v]
|
|
239
|
+
silent: true
|
|
240
|
+
cmds:
|
|
241
|
+
- |
|
|
242
|
+
# Read expected variables from .env and .env.local (combined, deduplicated)
|
|
243
|
+
expected_vars=$(cat .env .env.local 2>/dev/null | grep -E "^[A-Z_]+=" | cut -d= -f1 | sort -u)
|
|
244
|
+
|
|
245
|
+
if [ -z "$expected_vars" ]; then
|
|
246
|
+
echo "❌ No .env file found or no variables defined" >&2
|
|
247
|
+
exit 1
|
|
248
|
+
fi
|
|
249
|
+
|
|
250
|
+
# Track failures
|
|
251
|
+
failed=false
|
|
252
|
+
|
|
253
|
+
# Check each variable
|
|
254
|
+
for var in $expected_vars; do
|
|
255
|
+
value="${!var}"
|
|
256
|
+
|
|
257
|
+
# Check if variable is set
|
|
258
|
+
if [ -z "$value" ]; then
|
|
259
|
+
echo "❌ $var: NOT SET" >&2
|
|
260
|
+
failed=true
|
|
261
|
+
continue
|
|
262
|
+
fi
|
|
263
|
+
|
|
264
|
+
# Check if still in op:// format (not exported)
|
|
265
|
+
if [[ "$value" =~ ^op:// ]]; then
|
|
266
|
+
echo "❌ $var: NOT RESOLVED (run: source \$(task op:export))" >&2
|
|
267
|
+
failed=true
|
|
268
|
+
continue
|
|
269
|
+
fi
|
|
270
|
+
done
|
|
271
|
+
|
|
272
|
+
# Only exit with error if validation failed
|
|
273
|
+
if [ "$failed" = true ]; then
|
|
274
|
+
exit 1
|
|
275
|
+
fi
|
|
276
|
+
|
|
277
|
+
test:
|
|
278
|
+
desc: "Test GitHub token permissions using .env mapping"
|
|
279
|
+
aliases: [t]
|
|
280
|
+
silent: true
|
|
281
|
+
cmds:
|
|
282
|
+
- |
|
|
283
|
+
echo "GitHub Token Permission Test"
|
|
284
|
+
echo "============================"
|
|
285
|
+
echo ""
|
|
286
|
+
|
|
287
|
+
# Check gh CLI is installed
|
|
288
|
+
if ! command -v gh &> /dev/null; then
|
|
289
|
+
echo "❌ GitHub CLI not found. Install: brew install gh" >&2
|
|
290
|
+
exit 1
|
|
291
|
+
fi
|
|
292
|
+
|
|
293
|
+
# Get GITHUB_TOKEN reference from .env
|
|
294
|
+
github_token_ref=$(grep "^GITHUB_TOKEN=" .env | cut -d= -f2)
|
|
295
|
+
if [ -z "$github_token_ref" ]; then
|
|
296
|
+
echo "❌ GITHUB_TOKEN not found in .env" >&2
|
|
297
|
+
exit 1
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
# Resolve from 1Password using .env mapping
|
|
301
|
+
if [[ "$github_token_ref" =~ ^op:// ]]; then
|
|
302
|
+
export GITHUB_TOKEN=$(op read "$github_token_ref" 2>/dev/null)
|
|
303
|
+
if [ $? -ne 0 ]; then
|
|
304
|
+
echo "❌ Could not resolve GITHUB_TOKEN from 1Password" >&2
|
|
305
|
+
echo "Hint: Ensure 1Password is unlocked" >&2
|
|
306
|
+
exit 1
|
|
307
|
+
fi
|
|
308
|
+
else
|
|
309
|
+
export GITHUB_TOKEN="$github_token_ref"
|
|
310
|
+
fi
|
|
311
|
+
|
|
312
|
+
export GH_TOKEN="$GITHUB_TOKEN"
|
|
313
|
+
echo "Token loaded: ${GITHUB_TOKEN:0:10}..."
|
|
314
|
+
echo ""
|
|
315
|
+
|
|
316
|
+
# Get repository from git remote
|
|
317
|
+
REPO=$(git config --get remote.origin.url | sed -E "s|^.*[:/]([^/]+/[^/]+)(.git)?$|\1|" | sed "s/\.git$//")
|
|
318
|
+
echo "Testing: $REPO"
|
|
319
|
+
echo ""
|
|
320
|
+
|
|
321
|
+
# Test read permissions
|
|
322
|
+
echo "Testing read permissions..."
|
|
323
|
+
gh repo view "$REPO" --json name > /dev/null 2>&1 && echo " ✅ Read repository" || { echo " ❌ Read repository" >&2; exit 1; }
|
|
324
|
+
gh issue list --repo "$REPO" --limit 1 > /dev/null 2>&1 && echo " ✅ Read issues" || echo " ⚠️ Read issues"
|
|
325
|
+
gh pr list --repo "$REPO" --limit 1 > /dev/null 2>&1 && echo " ✅ Read PRs" || echo " ⚠️ Read PRs"
|
|
326
|
+
gh run list --repo "$REPO" --limit 1 > /dev/null 2>&1 && echo " ✅ Read workflows" || echo " ⚠️ Read workflows"
|
|
327
|
+
echo ""
|
|
328
|
+
|
|
329
|
+
# Test write restrictions (should fail)
|
|
330
|
+
echo "Testing write restrictions..."
|
|
331
|
+
! gh secret list --repo "$REPO" > /dev/null 2>&1 && echo " ✅ Cannot read secrets" || { echo " ❌ SECURITY: Can read secrets!" >&2; exit 1; }
|
|
332
|
+
|
|
333
|
+
TEMP_FILE="temp-test-$(date +%s).md"
|
|
334
|
+
if echo "test" | gh api "repos/$REPO/contents/$TEMP_FILE" --method PUT --field message="test" --field content="dGVzdA==" --silent > /dev/null 2>&1; then
|
|
335
|
+
echo " ❌ SECURITY: Can write files!" >&2
|
|
336
|
+
gh api "repos/$REPO/contents/$TEMP_FILE" --method DELETE --field message="cleanup" --field sha="$(gh api "repos/$REPO/contents/$TEMP_FILE" --jq .sha)" --silent 2>&1 || true
|
|
337
|
+
exit 1
|
|
338
|
+
else
|
|
339
|
+
echo " ✅ Cannot write files"
|
|
340
|
+
fi
|
|
341
|
+
|
|
342
|
+
WORKFLOW=$(gh api "repos/$REPO/actions/workflows" --jq ".workflows[0].path" 2>/dev/null)
|
|
343
|
+
if [ -n "$WORKFLOW" ]; then
|
|
344
|
+
! gh workflow run "$WORKFLOW" --repo "$REPO" > /dev/null 2>&1 && echo " ✅ Cannot trigger workflows" || { echo " ❌ SECURITY: Can trigger workflows!" >&2; exit 1; }
|
|
345
|
+
else
|
|
346
|
+
echo " ⚠️ No workflows to test"
|
|
347
|
+
fi
|
|
348
|
+
|
|
349
|
+
echo ""
|
|
350
|
+
echo "✅ All tests passed - token follows least privilege"
|