javi-forge 1.6.0 → 1.7.0
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/README.md +45 -1
- package/ci-local/README.md +56 -11
- package/ci-local/ci-local.ps1 +445 -0
- package/ci-local/ci-local.sh +52 -9
- package/ci-local/docker/python.Dockerfile +7 -0
- package/ci-local/hooks/commit-msg +120 -44
- package/ci-local/hooks/commit-msg.test.sh +286 -0
- package/ci-local/hooks/pre-commit +9 -1
- package/ci-local/hooks/pre-push +13 -2
- package/ci-local/install.ps1 +367 -0
- package/ci-local/install.sh +151 -5
- package/ci-local/uninstall.ps1 +85 -0
- package/ci-local/uninstall.sh +95 -0
- package/dist/cli/dispatch/ci.d.ts +12 -0
- package/dist/cli/dispatch/ci.js +38 -0
- package/dist/cli/dispatch/security.d.ts +11 -0
- package/dist/cli/dispatch/security.js +68 -0
- package/dist/cli/dispatch/simple-renderers.d.ts +16 -0
- package/dist/cli/dispatch/simple-renderers.js +65 -0
- package/dist/cli/dispatch/skill-publish.d.ts +15 -0
- package/dist/cli/dispatch/skill-publish.js +44 -0
- package/dist/cli/dispatch/skills-cmd.d.ts +13 -0
- package/dist/cli/dispatch/skills-cmd.js +93 -0
- package/dist/cli/dispatch/tdd.d.ts +11 -0
- package/dist/cli/dispatch/tdd.js +45 -0
- package/dist/cli/dispatch/types.d.ts +29 -0
- package/dist/cli/dispatch/types.js +2 -0
- package/dist/cli/dispatch/workflow.d.ts +11 -0
- package/dist/cli/dispatch/workflow.js +67 -0
- package/dist/cli/help.d.ts +127 -0
- package/dist/cli/help.js +138 -0
- package/dist/cli/runtime.d.ts +16 -0
- package/dist/cli/runtime.js +38 -0
- package/dist/cli/validators.d.ts +17 -0
- package/dist/cli/validators.js +35 -0
- package/dist/commands/analyze.d.ts +1 -1
- package/dist/commands/analyze.js +14 -16
- package/dist/commands/ci.d.ts +50 -3
- package/dist/commands/ci.js +537 -182
- package/dist/commands/doctor.d.ts +2 -2
- package/dist/commands/doctor.js +112 -62
- package/dist/commands/init/report.d.ts +13 -0
- package/dist/commands/init/report.js +13 -0
- package/dist/commands/init/steps/agent-skills.d.ts +13 -0
- package/dist/commands/init/steps/agent-skills.js +45 -0
- package/dist/commands/init/steps/ai-sync.d.ts +15 -0
- package/dist/commands/init/steps/ai-sync.js +62 -0
- package/dist/commands/init/steps/ci.d.ts +24 -0
- package/dist/commands/init/steps/ci.js +74 -0
- package/dist/commands/init/steps/claude-md.d.ts +14 -0
- package/dist/commands/init/steps/claude-md.js +54 -0
- package/dist/commands/init/steps/code-graph.d.ts +16 -0
- package/dist/commands/init/steps/code-graph.js +68 -0
- package/dist/commands/init/steps/context-dir.d.ts +13 -0
- package/dist/commands/init/steps/context-dir.js +47 -0
- package/dist/commands/init/steps/docker-deploy.d.ts +16 -0
- package/dist/commands/init/steps/docker-deploy.js +60 -0
- package/dist/commands/init/steps/ghagga.d.ts +15 -0
- package/dist/commands/init/steps/ghagga.js +58 -0
- package/dist/commands/init/steps/git.d.ts +25 -0
- package/dist/commands/init/steps/git.js +81 -0
- package/dist/commands/init/steps/gitignore.d.ts +13 -0
- package/dist/commands/init/steps/gitignore.js +39 -0
- package/dist/commands/init/steps/local-ai.d.ts +14 -0
- package/dist/commands/init/steps/local-ai.js +53 -0
- package/dist/commands/init/steps/manifest.d.ts +13 -0
- package/dist/commands/init/steps/manifest.js +58 -0
- package/dist/commands/init/steps/memory.d.ts +15 -0
- package/dist/commands/init/steps/memory.js +60 -0
- package/dist/commands/init/steps/mock.d.ts +13 -0
- package/dist/commands/init/steps/mock.js +64 -0
- package/dist/commands/init/steps/sdd.d.ts +12 -0
- package/dist/commands/init/steps/sdd.js +40 -0
- package/dist/commands/init/steps/security.d.ts +28 -0
- package/dist/commands/init/steps/security.js +103 -0
- package/dist/commands/init/types.d.ts +30 -0
- package/dist/commands/init/types.js +2 -0
- package/dist/commands/init.d.ts +5 -4
- package/dist/commands/init.js +42 -387
- package/dist/commands/llmstxt.d.ts +1 -1
- package/dist/commands/llmstxt.js +36 -34
- package/dist/commands/plugin.d.ts +10 -1
- package/dist/commands/plugin.js +92 -47
- package/dist/commands/security.d.ts +11 -5
- package/dist/commands/security.js +236 -77
- package/dist/commands/skills/analysis.d.ts +19 -0
- package/dist/commands/skills/analysis.js +211 -0
- package/dist/commands/skills/benchmark.d.ts +6 -0
- package/dist/commands/skills/benchmark.js +82 -0
- package/dist/commands/skills/constants.d.ts +10 -0
- package/dist/commands/skills/constants.js +27 -0
- package/dist/commands/skills/directives.d.ts +21 -0
- package/dist/commands/skills/directives.js +101 -0
- package/dist/commands/skills/parsing.d.ts +16 -0
- package/dist/commands/skills/parsing.js +108 -0
- package/dist/commands/skills/rules.d.ts +5 -0
- package/dist/commands/skills/rules.js +32 -0
- package/dist/commands/skills/scoring.d.ts +47 -0
- package/dist/commands/skills/scoring.js +306 -0
- package/dist/commands/skills.d.ts +8 -69
- package/dist/commands/skills.js +9 -490
- package/dist/commands/tdd-pipeline.d.ts +17 -0
- package/dist/commands/tdd-pipeline.js +144 -0
- package/dist/commands/tdd.d.ts +1 -1
- package/dist/commands/tdd.js +21 -18
- package/dist/commands/workflow.d.ts +23 -0
- package/dist/commands/workflow.js +116 -0
- package/dist/constants.d.ts +15 -1
- package/dist/constants.js +161 -122
- package/dist/index.js +43 -280
- package/dist/lib/agent-skills.d.ts +36 -1
- package/dist/lib/agent-skills.js +168 -19
- package/dist/lib/atlassian-mcp.d.ts +42 -0
- package/dist/lib/atlassian-mcp.js +98 -0
- package/dist/lib/auto-skill-install.d.ts +37 -0
- package/dist/lib/auto-skill-install.js +91 -0
- package/dist/lib/auto-wire.d.ts +20 -0
- package/dist/lib/auto-wire.js +240 -0
- package/dist/lib/ci-config.d.ts +65 -0
- package/dist/lib/ci-config.js +297 -0
- package/dist/lib/claudemd.d.ts +13 -1
- package/dist/lib/claudemd.js +174 -24
- package/dist/lib/codex-export.d.ts +1 -1
- package/dist/lib/codex-export.js +26 -32
- package/dist/lib/common.d.ts +1 -1
- package/dist/lib/common.js +52 -44
- package/dist/lib/context.d.ts +17 -2
- package/dist/lib/context.js +142 -13
- package/dist/lib/crash-recovery.d.ts +34 -0
- package/dist/lib/crash-recovery.js +123 -0
- package/dist/lib/docker.d.ts +23 -2
- package/dist/lib/docker.js +168 -131
- package/dist/lib/exec.d.ts +10 -0
- package/dist/lib/exec.js +11 -0
- package/dist/lib/frontmatter.d.ts +1 -1
- package/dist/lib/frontmatter.js +29 -15
- package/dist/lib/harness-audit.d.ts +35 -0
- package/dist/lib/harness-audit.js +277 -0
- package/dist/lib/parallel-batch.d.ts +42 -0
- package/dist/lib/parallel-batch.js +88 -0
- package/dist/lib/plugin.d.ts +9 -3
- package/dist/lib/plugin.js +127 -70
- package/dist/lib/secret-scanner.d.ts +30 -0
- package/dist/lib/secret-scanner.js +274 -0
- package/dist/lib/security-analysis.d.ts +74 -0
- package/dist/lib/security-analysis.js +489 -0
- package/dist/lib/skill-publish.d.ts +40 -0
- package/dist/lib/skill-publish.js +164 -0
- package/dist/lib/skill-scanner.d.ts +63 -0
- package/dist/lib/skill-scanner.js +383 -0
- package/dist/lib/stack-detector.d.ts +38 -0
- package/dist/lib/stack-detector.js +207 -0
- package/dist/lib/supply-chain.d.ts +23 -0
- package/dist/lib/supply-chain.js +126 -0
- package/dist/lib/team-presets.d.ts +53 -0
- package/dist/lib/team-presets.js +201 -0
- package/dist/lib/template.d.ts +16 -1
- package/dist/lib/template.js +46 -17
- package/dist/lib/workflow/discovery.d.ts +27 -0
- package/dist/lib/workflow/discovery.js +85 -0
- package/dist/lib/workflow/index.d.ts +5 -0
- package/dist/lib/workflow/index.js +5 -0
- package/dist/lib/workflow/parser.d.ts +16 -0
- package/dist/lib/workflow/parser.js +198 -0
- package/dist/lib/workflow/renderer.d.ts +9 -0
- package/dist/lib/workflow/renderer.js +152 -0
- package/dist/lib/workflow/validator.d.ts +10 -0
- package/dist/lib/workflow/validator.js +189 -0
- package/dist/tasks/index.d.ts +4 -0
- package/dist/tasks/index.js +4 -0
- package/dist/tasks/scaffold-tasks.d.ts +3 -0
- package/dist/tasks/scaffold-tasks.js +14 -0
- package/dist/tasks/task-id.d.ts +30 -0
- package/dist/tasks/task-id.js +59 -0
- package/dist/tasks/task-tracker.d.ts +15 -0
- package/dist/tasks/task-tracker.js +81 -0
- package/dist/types/index.d.ts +134 -6
- package/dist/types/index.js +11 -1
- package/dist/ui/AnalyzeUI.d.ts +1 -1
- package/dist/ui/AnalyzeUI.js +38 -39
- package/dist/ui/App.d.ts +5 -3
- package/dist/ui/App.js +86 -46
- package/dist/ui/AutoSkills.d.ts +9 -0
- package/dist/ui/AutoSkills.js +124 -0
- package/dist/ui/CI.d.ts +2 -2
- package/dist/ui/CI.js +24 -26
- package/dist/ui/CIContext.d.ts +1 -1
- package/dist/ui/CIContext.js +2 -2
- package/dist/ui/CISelector.d.ts +2 -2
- package/dist/ui/CISelector.js +23 -15
- package/dist/ui/Doctor.d.ts +1 -1
- package/dist/ui/Doctor.js +35 -29
- package/dist/ui/Header.d.ts +1 -1
- package/dist/ui/Header.js +14 -14
- package/dist/ui/HookProfileSelector.d.ts +9 -0
- package/dist/ui/HookProfileSelector.js +54 -0
- package/dist/ui/LlmsTxt.d.ts +1 -1
- package/dist/ui/LlmsTxt.js +31 -22
- package/dist/ui/MemorySelector.d.ts +2 -2
- package/dist/ui/MemorySelector.js +28 -16
- package/dist/ui/NameInput.d.ts +1 -1
- package/dist/ui/NameInput.js +21 -21
- package/dist/ui/OptionSelector.d.ts +6 -2
- package/dist/ui/OptionSelector.js +83 -32
- package/dist/ui/Plugin.d.ts +4 -3
- package/dist/ui/Plugin.js +78 -35
- package/dist/ui/Progress.d.ts +3 -3
- package/dist/ui/Progress.js +23 -22
- package/dist/ui/Skills.d.ts +2 -2
- package/dist/ui/Skills.js +61 -32
- package/dist/ui/StackSelector.d.ts +2 -2
- package/dist/ui/StackSelector.js +27 -17
- package/dist/ui/Summary.d.ts +3 -3
- package/dist/ui/Summary.js +60 -50
- package/dist/ui/Welcome.d.ts +1 -1
- package/dist/ui/Welcome.js +15 -16
- package/dist/ui/theme.d.ts +1 -1
- package/dist/ui/theme.js +6 -6
- package/lib/common.psm1 +167 -0
- package/lib/common.sh +30 -0
- package/package.json +46 -24
- package/templates/common/atlassian/mcp-atlassian-snippet.json +16 -0
- package/templates/common/repoforge/mcp-repoforge-snippet.json +11 -0
- package/templates/common/repoforge/repoforge.yaml +34 -0
- package/templates/github/deploy-docker-zero-downtime.yml +140 -0
- package/templates/github/repoforge-graph.yml +45 -0
- package/templates/gitlab/deploy-docker-zero-downtime.yml +57 -0
- package/templates/local-ai/.env.example +17 -0
- package/templates/local-ai/docker-compose.yml +95 -0
- package/templates/security-hooks/claude-settings-security.json +30 -0
- package/templates/security-hooks/commit-msg-signing +29 -0
- package/templates/security-hooks/pre-commit-permissions +74 -0
- package/templates/security-hooks/pre-commit-secrets +74 -0
- package/templates/security-hooks/pre-push-branch-protection +62 -0
- package/templates/security-hooks/pre-push-deps +83 -0
- package/templates/security-hooks/pre-push-signing +67 -0
- package/templates/woodpecker/deploy-docker-zero-downtime.yml +50 -0
- package/templates/workflows/ci-pipeline.dot +15 -0
- package/templates/workflows/feature-flow.dot +21 -0
- package/templates/workflows/release.dot +16 -0
- package/dist/__integration__/helpers.d.ts +0 -20
- package/dist/__integration__/helpers.d.ts.map +0 -1
- package/dist/__integration__/helpers.js +0 -31
- package/dist/__integration__/helpers.js.map +0 -1
- package/dist/commands/analyze.d.ts.map +0 -1
- package/dist/commands/analyze.js.map +0 -1
- package/dist/commands/ci.d.ts.map +0 -1
- package/dist/commands/ci.js.map +0 -1
- package/dist/commands/doctor.d.ts.map +0 -1
- package/dist/commands/doctor.js.map +0 -1
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/llmstxt.d.ts.map +0 -1
- package/dist/commands/llmstxt.js.map +0 -1
- package/dist/commands/plugin.d.ts.map +0 -1
- package/dist/commands/plugin.js.map +0 -1
- package/dist/commands/security.d.ts.map +0 -1
- package/dist/commands/security.js.map +0 -1
- package/dist/commands/skills.d.ts.map +0 -1
- package/dist/commands/skills.js.map +0 -1
- package/dist/commands/tdd.d.ts.map +0 -1
- package/dist/commands/tdd.js.map +0 -1
- package/dist/constants.d.ts.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lib/agent-skills.d.ts.map +0 -1
- package/dist/lib/agent-skills.js.map +0 -1
- package/dist/lib/claudemd.d.ts.map +0 -1
- package/dist/lib/claudemd.js.map +0 -1
- package/dist/lib/codex-export.d.ts.map +0 -1
- package/dist/lib/codex-export.js.map +0 -1
- package/dist/lib/common.d.ts.map +0 -1
- package/dist/lib/common.js.map +0 -1
- package/dist/lib/context.d.ts.map +0 -1
- package/dist/lib/context.js.map +0 -1
- package/dist/lib/docker.d.ts.map +0 -1
- package/dist/lib/docker.js.map +0 -1
- package/dist/lib/frontmatter.d.ts.map +0 -1
- package/dist/lib/frontmatter.js.map +0 -1
- package/dist/lib/plugin.d.ts.map +0 -1
- package/dist/lib/plugin.js.map +0 -1
- package/dist/lib/template.d.ts.map +0 -1
- package/dist/lib/template.js.map +0 -1
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/index.js.map +0 -1
- package/dist/ui/AnalyzeUI.d.ts.map +0 -1
- package/dist/ui/AnalyzeUI.js.map +0 -1
- package/dist/ui/App.d.ts.map +0 -1
- package/dist/ui/App.js.map +0 -1
- package/dist/ui/CI.d.ts.map +0 -1
- package/dist/ui/CI.js.map +0 -1
- package/dist/ui/CIContext.d.ts.map +0 -1
- package/dist/ui/CIContext.js.map +0 -1
- package/dist/ui/CISelector.d.ts.map +0 -1
- package/dist/ui/CISelector.js.map +0 -1
- package/dist/ui/Doctor.d.ts.map +0 -1
- package/dist/ui/Doctor.js.map +0 -1
- package/dist/ui/Header.d.ts.map +0 -1
- package/dist/ui/Header.js.map +0 -1
- package/dist/ui/LlmsTxt.d.ts.map +0 -1
- package/dist/ui/LlmsTxt.js.map +0 -1
- package/dist/ui/MemorySelector.d.ts.map +0 -1
- package/dist/ui/MemorySelector.js.map +0 -1
- package/dist/ui/NameInput.d.ts.map +0 -1
- package/dist/ui/NameInput.js.map +0 -1
- package/dist/ui/OptionSelector.d.ts.map +0 -1
- package/dist/ui/OptionSelector.js.map +0 -1
- package/dist/ui/Plugin.d.ts.map +0 -1
- package/dist/ui/Plugin.js.map +0 -1
- package/dist/ui/Progress.d.ts.map +0 -1
- package/dist/ui/Progress.js.map +0 -1
- package/dist/ui/Skills.d.ts.map +0 -1
- package/dist/ui/Skills.js.map +0 -1
- package/dist/ui/StackSelector.d.ts.map +0 -1
- package/dist/ui/StackSelector.js.map +0 -1
- package/dist/ui/Summary.d.ts.map +0 -1
- package/dist/ui/Summary.js.map +0 -1
- package/dist/ui/Welcome.d.ts.map +0 -1
- package/dist/ui/Welcome.js.map +0 -1
- package/dist/ui/theme.d.ts.map +0 -1
- package/dist/ui/theme.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,72 +1,94 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "javi-forge",
|
|
3
|
-
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Project scaffolding and AI-ready CI bootstrap",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"javi-forge": "
|
|
7
|
+
"javi-forge": "dist/index.js"
|
|
8
8
|
},
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"dev": "tsx watch src/index.tsx",
|
|
12
12
|
"start": "node dist/index.js",
|
|
13
13
|
"typecheck": "tsc --noEmit",
|
|
14
|
+
"typecheck:test": "tsc --project tsconfig.test.json --noEmit",
|
|
14
15
|
"test": "vitest run",
|
|
15
16
|
"test:watch": "vitest",
|
|
16
17
|
"test:coverage": "vitest run --coverage",
|
|
17
|
-
"test:mutation": "stryker run"
|
|
18
|
+
"test:mutation": "stryker run",
|
|
19
|
+
"test:hooks": "bash ci-local/hooks/commit-msg.test.sh",
|
|
20
|
+
"lint": "biome check src/",
|
|
21
|
+
"lint:fix": "biome check --write src/",
|
|
22
|
+
"format": "biome format --write src/",
|
|
23
|
+
"validate": "pnpm typecheck && pnpm typecheck:test && pnpm lint && pnpm test",
|
|
24
|
+
"package:check": "npm pack --dry-run --json --cache /tmp/javi-forge-npm-pack-cache > /tmp/javi-forge-pack.json && node scripts/verify-package-contents.mjs /tmp/javi-forge-pack.json"
|
|
18
25
|
},
|
|
19
26
|
"files": [
|
|
20
|
-
"dist
|
|
27
|
+
"dist/**/*.js",
|
|
28
|
+
"dist/**/*.d.ts",
|
|
29
|
+
"!dist/__integration__/**",
|
|
30
|
+
"!dist/e2e/**",
|
|
21
31
|
"ci-local/",
|
|
22
32
|
"modules/",
|
|
23
33
|
"templates/",
|
|
24
34
|
"workflows/",
|
|
25
35
|
"lib/",
|
|
26
|
-
"!dist/**/*.test.*",
|
|
27
|
-
"!dist/**/__snapshots__",
|
|
28
|
-
"package.json",
|
|
29
36
|
"README.md",
|
|
37
|
+
"LICENSE*",
|
|
30
38
|
".gitignore.template"
|
|
31
39
|
],
|
|
32
40
|
"author": "JNZader",
|
|
33
41
|
"license": "MIT",
|
|
34
42
|
"repository": {
|
|
35
43
|
"type": "git",
|
|
36
|
-
"url": "https://github.com/JNZader/javi-forge"
|
|
44
|
+
"url": "git+https://github.com/JNZader/javi-forge.git"
|
|
37
45
|
},
|
|
38
46
|
"engines": {
|
|
39
|
-
"node": ">=
|
|
47
|
+
"node": ">=22"
|
|
40
48
|
},
|
|
41
49
|
"dependencies": {
|
|
42
50
|
"chalk": "^5.6.2",
|
|
43
|
-
"fs-extra": "^11.3.
|
|
51
|
+
"fs-extra": "^11.3.5",
|
|
44
52
|
"glob": "^13.0.6",
|
|
45
|
-
"ink": "^
|
|
53
|
+
"ink": "^7.0.3",
|
|
46
54
|
"ink-spinner": "^5.0.0",
|
|
47
55
|
"meow": "^14.1.0",
|
|
48
|
-
"react": "^19.2.
|
|
56
|
+
"react": "^19.2.6",
|
|
49
57
|
"update-notifier": "^7.3.1",
|
|
50
|
-
"yaml": "^2.
|
|
58
|
+
"yaml": "^2.9.0"
|
|
51
59
|
},
|
|
52
60
|
"devDependencies": {
|
|
61
|
+
"@biomejs/biome": "^2.4.15",
|
|
53
62
|
"@semantic-release/changelog": "^6.0.3",
|
|
54
63
|
"@semantic-release/exec": "^7.1.0",
|
|
55
64
|
"@semantic-release/git": "^10.0.1",
|
|
56
|
-
"@semantic-release/github": "^12.0.
|
|
57
|
-
"@stryker-mutator/core": "^9.6.
|
|
58
|
-
"@stryker-mutator/typescript-checker": "^9.6.
|
|
59
|
-
"@stryker-mutator/vitest-runner": "^9.6.
|
|
65
|
+
"@semantic-release/github": "^12.0.8",
|
|
66
|
+
"@stryker-mutator/core": "^9.6.1",
|
|
67
|
+
"@stryker-mutator/typescript-checker": "^9.6.1",
|
|
68
|
+
"@stryker-mutator/vitest-runner": "^9.6.1",
|
|
60
69
|
"@types/fs-extra": "^11.0.4",
|
|
61
|
-
"@types/
|
|
62
|
-
"@types/node": "^25.5.0",
|
|
70
|
+
"@types/node": "^25.8.0",
|
|
63
71
|
"@types/react": "^19.2.14",
|
|
64
72
|
"@types/update-notifier": "^6.0.8",
|
|
65
|
-
"@vitest/coverage-v8": "^4.1.
|
|
66
|
-
"conventional-changelog-conventionalcommits": "^9.3.
|
|
73
|
+
"@vitest/coverage-v8": "^4.1.6",
|
|
74
|
+
"conventional-changelog-conventionalcommits": "^9.3.1",
|
|
75
|
+
"ink-testing-library": "^4.0.0",
|
|
67
76
|
"semantic-release": "^25.0.3",
|
|
68
|
-
"tsx": "^4.
|
|
69
|
-
"typescript": "^
|
|
70
|
-
"
|
|
77
|
+
"tsx": "^4.22.1",
|
|
78
|
+
"typescript": "^6.0.3",
|
|
79
|
+
"vite": "^8.0.13",
|
|
80
|
+
"vitest": "^4.1.6"
|
|
81
|
+
},
|
|
82
|
+
"pnpm": {
|
|
83
|
+
"overrides": {
|
|
84
|
+
"handlebars": "^4.7.9",
|
|
85
|
+
"picomatch": "^4.0.4",
|
|
86
|
+
"brace-expansion": "^5.0.5",
|
|
87
|
+
"lodash": "^4.18.0",
|
|
88
|
+
"lodash-es": "^4.18.0",
|
|
89
|
+
"fast-uri": "^3.1.2",
|
|
90
|
+
"postcss": "^8.5.10",
|
|
91
|
+
"vite": "^8.0.5"
|
|
92
|
+
}
|
|
71
93
|
}
|
|
72
94
|
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"mcpServers": {
|
|
3
|
+
"atlassian": {
|
|
4
|
+
"command": "uvx",
|
|
5
|
+
"args": ["mcp-atlassian"],
|
|
6
|
+
"env": {
|
|
7
|
+
"CONFLUENCE_URL": "__CONFLUENCE_URL__",
|
|
8
|
+
"CONFLUENCE_USERNAME": "__CONFLUENCE_USERNAME__",
|
|
9
|
+
"CONFLUENCE_API_TOKEN": "__CONFLUENCE_API_TOKEN__",
|
|
10
|
+
"JIRA_URL": "__JIRA_URL__",
|
|
11
|
+
"JIRA_USERNAME": "__JIRA_USERNAME__",
|
|
12
|
+
"JIRA_API_TOKEN": "__JIRA_API_TOKEN__"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# ===========================================
|
|
2
|
+
# RepoForge Graph Configuration
|
|
3
|
+
# ===========================================
|
|
4
|
+
# Docs: https://github.com/JNZader/repoforge
|
|
5
|
+
# ===========================================
|
|
6
|
+
|
|
7
|
+
graph:
|
|
8
|
+
# Graph type: calls | imports | dependencies
|
|
9
|
+
type: calls
|
|
10
|
+
|
|
11
|
+
# Output format: json | dot | mermaid
|
|
12
|
+
output: json
|
|
13
|
+
|
|
14
|
+
# Where to store the generated graph artifact
|
|
15
|
+
artifact: .repoforge/call-graph.json
|
|
16
|
+
|
|
17
|
+
# Directories to include (globs supported)
|
|
18
|
+
include:
|
|
19
|
+
- src/**
|
|
20
|
+
|
|
21
|
+
# Directories to exclude
|
|
22
|
+
exclude:
|
|
23
|
+
- node_modules/**
|
|
24
|
+
- dist/**
|
|
25
|
+
- coverage/**
|
|
26
|
+
- '**/*.test.*'
|
|
27
|
+
- '**/*.spec.*'
|
|
28
|
+
|
|
29
|
+
query:
|
|
30
|
+
# Enable MCP-based code intelligence queries
|
|
31
|
+
mcp: true
|
|
32
|
+
|
|
33
|
+
# Max depth for transitive dependency lookups
|
|
34
|
+
max_depth: 5
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# ===========================================
|
|
2
|
+
# Zero-Downtime Docker Deploy (docker rollout)
|
|
3
|
+
# ===========================================
|
|
4
|
+
# Copy to: .github/workflows/deploy.yml
|
|
5
|
+
#
|
|
6
|
+
# Requires:
|
|
7
|
+
# - SSH access to the deploy target (secrets.DEPLOY_HOST, secrets.DEPLOY_USER, secrets.DEPLOY_KEY)
|
|
8
|
+
# - docker-rollout installed on the target: https://github.com/Wowu/docker-rollout
|
|
9
|
+
# - A docker-compose.yml on the target with healthcheck-enabled services
|
|
10
|
+
#
|
|
11
|
+
# Flow:
|
|
12
|
+
# 1. Build & push image to registry
|
|
13
|
+
# 2. SSH into deploy target
|
|
14
|
+
# 3. Pull new image
|
|
15
|
+
# 4. `docker rollout <service>` — spins up new container, waits for healthcheck, drains old
|
|
16
|
+
# ===========================================
|
|
17
|
+
|
|
18
|
+
name: Deploy (Zero-Downtime)
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
push:
|
|
22
|
+
branches: [main]
|
|
23
|
+
paths-ignore:
|
|
24
|
+
- '**/*.md'
|
|
25
|
+
- '.gitignore'
|
|
26
|
+
workflow_dispatch:
|
|
27
|
+
inputs:
|
|
28
|
+
service:
|
|
29
|
+
description: 'Service to deploy (from docker-compose.yml)'
|
|
30
|
+
required: true
|
|
31
|
+
default: '__SERVICE_NAME__'
|
|
32
|
+
skip_build:
|
|
33
|
+
description: 'Skip image build (deploy existing latest)'
|
|
34
|
+
default: false
|
|
35
|
+
type: boolean
|
|
36
|
+
|
|
37
|
+
permissions:
|
|
38
|
+
contents: read
|
|
39
|
+
packages: write
|
|
40
|
+
|
|
41
|
+
concurrency:
|
|
42
|
+
group: deploy-${{ github.ref }}
|
|
43
|
+
cancel-in-progress: false # Never cancel in-progress deploys
|
|
44
|
+
|
|
45
|
+
env:
|
|
46
|
+
REGISTRY: ghcr.io
|
|
47
|
+
IMAGE_NAME: ${{ github.repository }}
|
|
48
|
+
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
|
|
49
|
+
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
|
|
50
|
+
|
|
51
|
+
jobs:
|
|
52
|
+
build-and-push:
|
|
53
|
+
if: ${{ github.event.inputs.skip_build != 'true' }}
|
|
54
|
+
runs-on: ubuntu-latest
|
|
55
|
+
outputs:
|
|
56
|
+
image_tag: ${{ steps.meta.outputs.tags }}
|
|
57
|
+
steps:
|
|
58
|
+
- uses: actions/checkout@v4
|
|
59
|
+
|
|
60
|
+
- name: Log in to Container Registry
|
|
61
|
+
uses: docker/login-action@v3
|
|
62
|
+
with:
|
|
63
|
+
registry: ${{ env.REGISTRY }}
|
|
64
|
+
username: ${{ github.actor }}
|
|
65
|
+
password: ${{ secrets.GITHUB_TOKEN }}
|
|
66
|
+
|
|
67
|
+
- name: Extract metadata
|
|
68
|
+
id: meta
|
|
69
|
+
uses: docker/metadata-action@v5
|
|
70
|
+
with:
|
|
71
|
+
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
|
72
|
+
tags: |
|
|
73
|
+
type=sha
|
|
74
|
+
type=raw,value=latest
|
|
75
|
+
|
|
76
|
+
- name: Build and push
|
|
77
|
+
uses: docker/build-push-action@v5
|
|
78
|
+
with:
|
|
79
|
+
context: .
|
|
80
|
+
push: true
|
|
81
|
+
tags: ${{ steps.meta.outputs.tags }}
|
|
82
|
+
labels: ${{ steps.meta.outputs.labels }}
|
|
83
|
+
|
|
84
|
+
deploy:
|
|
85
|
+
needs: [build-and-push]
|
|
86
|
+
if: always() && (needs.build-and-push.result == 'success' || github.event.inputs.skip_build == 'true')
|
|
87
|
+
runs-on: ubuntu-latest
|
|
88
|
+
environment: production
|
|
89
|
+
steps:
|
|
90
|
+
- name: Deploy via SSH + docker rollout
|
|
91
|
+
uses: appleboy/ssh-action@v1
|
|
92
|
+
with:
|
|
93
|
+
host: ${{ env.DEPLOY_HOST }}
|
|
94
|
+
username: ${{ env.DEPLOY_USER }}
|
|
95
|
+
key: ${{ secrets.DEPLOY_KEY }}
|
|
96
|
+
script: |
|
|
97
|
+
set -euo pipefail
|
|
98
|
+
|
|
99
|
+
cd ${{ secrets.DEPLOY_DIR || '~/app' }}
|
|
100
|
+
|
|
101
|
+
# Pull latest images
|
|
102
|
+
docker compose pull
|
|
103
|
+
|
|
104
|
+
# Zero-downtime rollout for the target service
|
|
105
|
+
SERVICE="${{ github.event.inputs.service || '__SERVICE_NAME__' }}"
|
|
106
|
+
echo "::group::Rolling out ${SERVICE}"
|
|
107
|
+
docker rollout "${SERVICE}"
|
|
108
|
+
echo "::endgroup::"
|
|
109
|
+
|
|
110
|
+
# Cleanup dangling images
|
|
111
|
+
docker image prune -f
|
|
112
|
+
|
|
113
|
+
- name: Verify deployment
|
|
114
|
+
uses: appleboy/ssh-action@v1
|
|
115
|
+
with:
|
|
116
|
+
host: ${{ env.DEPLOY_HOST }}
|
|
117
|
+
username: ${{ env.DEPLOY_USER }}
|
|
118
|
+
key: ${{ secrets.DEPLOY_KEY }}
|
|
119
|
+
script: |
|
|
120
|
+
set -euo pipefail
|
|
121
|
+
cd ${{ secrets.DEPLOY_DIR || '~/app' }}
|
|
122
|
+
SERVICE="${{ github.event.inputs.service || '__SERVICE_NAME__' }}"
|
|
123
|
+
|
|
124
|
+
# Wait for healthcheck (max 60s)
|
|
125
|
+
TIMEOUT=60
|
|
126
|
+
ELAPSED=0
|
|
127
|
+
while [ $ELAPSED -lt $TIMEOUT ]; do
|
|
128
|
+
HEALTH=$(docker compose ps "${SERVICE}" --format json | jq -r '.[0].Health // "none"' 2>/dev/null || echo "unknown")
|
|
129
|
+
if [ "$HEALTH" = "healthy" ]; then
|
|
130
|
+
echo "✅ ${SERVICE} is healthy"
|
|
131
|
+
exit 0
|
|
132
|
+
fi
|
|
133
|
+
sleep 5
|
|
134
|
+
ELAPSED=$((ELAPSED + 5))
|
|
135
|
+
echo "⏳ Waiting for healthcheck... (${ELAPSED}s/${TIMEOUT}s)"
|
|
136
|
+
done
|
|
137
|
+
|
|
138
|
+
echo "❌ ${SERVICE} did not become healthy within ${TIMEOUT}s"
|
|
139
|
+
docker compose logs --tail=50 "${SERVICE}"
|
|
140
|
+
exit 1
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# ===========================================
|
|
2
|
+
# RepoForge Call Graph — keep graph fresh on every push
|
|
3
|
+
# ===========================================
|
|
4
|
+
# Copy to: .github/workflows/repoforge-graph.yml
|
|
5
|
+
# ===========================================
|
|
6
|
+
|
|
7
|
+
name: RepoForge Graph
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
paths-ignore:
|
|
13
|
+
- '**/*.md'
|
|
14
|
+
- '.gitignore'
|
|
15
|
+
pull_request:
|
|
16
|
+
branches: [main]
|
|
17
|
+
paths-ignore:
|
|
18
|
+
- '**/*.md'
|
|
19
|
+
- '.gitignore'
|
|
20
|
+
|
|
21
|
+
permissions:
|
|
22
|
+
contents: read
|
|
23
|
+
|
|
24
|
+
concurrency:
|
|
25
|
+
group: repoforge-graph-${{ github.ref }}
|
|
26
|
+
cancel-in-progress: true
|
|
27
|
+
|
|
28
|
+
jobs:
|
|
29
|
+
graph:
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
steps:
|
|
32
|
+
- uses: actions/checkout@v4
|
|
33
|
+
|
|
34
|
+
- name: Install repoforge
|
|
35
|
+
run: npm install -g repoforge
|
|
36
|
+
|
|
37
|
+
- name: Generate call graph
|
|
38
|
+
run: repoforge graph --type calls --output .repoforge/call-graph.json
|
|
39
|
+
|
|
40
|
+
- name: Upload graph artifact
|
|
41
|
+
uses: actions/upload-artifact@v4
|
|
42
|
+
with:
|
|
43
|
+
name: call-graph
|
|
44
|
+
path: .repoforge/call-graph.json
|
|
45
|
+
retention-days: 30
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# ===========================================
|
|
2
|
+
# Zero-Downtime Docker Deploy (docker rollout)
|
|
3
|
+
# ===========================================
|
|
4
|
+
# Merge into: .gitlab-ci.yml
|
|
5
|
+
#
|
|
6
|
+
# Requires:
|
|
7
|
+
# - CI/CD variables: DEPLOY_HOST, DEPLOY_USER, DEPLOY_KEY, DEPLOY_DIR
|
|
8
|
+
# - docker-rollout installed on target: https://github.com/Wowu/docker-rollout
|
|
9
|
+
# - A docker-compose.yml on the target with healthcheck-enabled services
|
|
10
|
+
# ===========================================
|
|
11
|
+
|
|
12
|
+
stages:
|
|
13
|
+
- build
|
|
14
|
+
- deploy
|
|
15
|
+
|
|
16
|
+
variables:
|
|
17
|
+
SERVICE_NAME: "__SERVICE_NAME__"
|
|
18
|
+
|
|
19
|
+
build-image:
|
|
20
|
+
stage: build
|
|
21
|
+
image: docker:latest
|
|
22
|
+
services:
|
|
23
|
+
- docker:dind
|
|
24
|
+
before_script:
|
|
25
|
+
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY"
|
|
26
|
+
script:
|
|
27
|
+
- docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" -t "$CI_REGISTRY_IMAGE:latest" .
|
|
28
|
+
- docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA"
|
|
29
|
+
- docker push "$CI_REGISTRY_IMAGE:latest"
|
|
30
|
+
only:
|
|
31
|
+
- main
|
|
32
|
+
|
|
33
|
+
deploy-zero-downtime:
|
|
34
|
+
stage: deploy
|
|
35
|
+
image: alpine:latest
|
|
36
|
+
needs: ["build-image"]
|
|
37
|
+
before_script:
|
|
38
|
+
- apk add --no-cache openssh-client
|
|
39
|
+
- eval "$(ssh-agent -s)"
|
|
40
|
+
- echo "$DEPLOY_KEY" | ssh-add -
|
|
41
|
+
- mkdir -p ~/.ssh && chmod 700 ~/.ssh
|
|
42
|
+
- ssh-keyscan "$DEPLOY_HOST" >> ~/.ssh/known_hosts
|
|
43
|
+
script:
|
|
44
|
+
- |
|
|
45
|
+
ssh "$DEPLOY_USER@$DEPLOY_HOST" << 'ENDSSH'
|
|
46
|
+
set -euo pipefail
|
|
47
|
+
cd ${DEPLOY_DIR:-~/app}
|
|
48
|
+
docker compose pull
|
|
49
|
+
docker rollout "${SERVICE_NAME}"
|
|
50
|
+
docker image prune -f
|
|
51
|
+
echo "Deploy complete"
|
|
52
|
+
ENDSSH
|
|
53
|
+
environment:
|
|
54
|
+
name: production
|
|
55
|
+
only:
|
|
56
|
+
- main
|
|
57
|
+
when: manual
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Local AI Stack — Environment Variables
|
|
2
|
+
# Copy to .env in your project: cp .env.example .env
|
|
3
|
+
|
|
4
|
+
# ── Ollama ──────────────────────────────────────────────────────────────────
|
|
5
|
+
OLLAMA_PORT=11434
|
|
6
|
+
|
|
7
|
+
# ── Open WebUI ──────────────────────────────────────────────────────────────
|
|
8
|
+
WEBUI_PORT=3000
|
|
9
|
+
WEBUI_AUTH=false
|
|
10
|
+
|
|
11
|
+
# ── n8n ─────────────────────────────────────────────────────────────────────
|
|
12
|
+
N8N_PORT=5678
|
|
13
|
+
|
|
14
|
+
# ── Supabase (Postgres) ────────────────────────────────────────────────────
|
|
15
|
+
SUPABASE_DB_PORT=5432
|
|
16
|
+
SUPABASE_DB_PASSWORD=postgres
|
|
17
|
+
SUPABASE_DB_NAME=app
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Local AI Development Stack
|
|
2
|
+
# Generated by javi-forge — https://github.com/JNZader/javi-forge
|
|
3
|
+
#
|
|
4
|
+
# Usage:
|
|
5
|
+
# docker compose up -d # Start Ollama (core)
|
|
6
|
+
# docker compose --profile ui up -d # Start Ollama + Open WebUI
|
|
7
|
+
# docker compose --profile auto up -d # Start Ollama + n8n + Open WebUI
|
|
8
|
+
# docker compose --profile full up -d # Start everything
|
|
9
|
+
#
|
|
10
|
+
# Pull a model after starting:
|
|
11
|
+
# docker exec ollama ollama pull llama3.2
|
|
12
|
+
# docker exec ollama ollama pull codellama
|
|
13
|
+
|
|
14
|
+
services:
|
|
15
|
+
# ── Core: Ollama (local LLM inference) ────────────────────────────────────
|
|
16
|
+
ollama:
|
|
17
|
+
image: ollama/ollama:latest
|
|
18
|
+
container_name: ollama
|
|
19
|
+
restart: unless-stopped
|
|
20
|
+
ports:
|
|
21
|
+
- "${OLLAMA_PORT:-11434}:11434"
|
|
22
|
+
volumes:
|
|
23
|
+
- ollama_data:/root/.ollama
|
|
24
|
+
environment:
|
|
25
|
+
- OLLAMA_HOST=0.0.0.0
|
|
26
|
+
# Uncomment for NVIDIA GPU support:
|
|
27
|
+
# deploy:
|
|
28
|
+
# resources:
|
|
29
|
+
# reservations:
|
|
30
|
+
# devices:
|
|
31
|
+
# - driver: nvidia
|
|
32
|
+
# count: all
|
|
33
|
+
# capabilities: [gpu]
|
|
34
|
+
healthcheck:
|
|
35
|
+
test: ["CMD-SHELL", "curl -f http://localhost:11434/api/tags || exit 1"]
|
|
36
|
+
interval: 30s
|
|
37
|
+
timeout: 10s
|
|
38
|
+
retries: 3
|
|
39
|
+
start_period: 10s
|
|
40
|
+
|
|
41
|
+
# ── Optional: Open WebUI (chat interface) ─────────────────────────────────
|
|
42
|
+
open-webui:
|
|
43
|
+
image: ghcr.io/open-webui/open-webui:main
|
|
44
|
+
container_name: open-webui
|
|
45
|
+
profiles: ["ui", "auto", "full"]
|
|
46
|
+
restart: unless-stopped
|
|
47
|
+
ports:
|
|
48
|
+
- "${WEBUI_PORT:-3000}:8080"
|
|
49
|
+
volumes:
|
|
50
|
+
- open_webui_data:/app/backend/data
|
|
51
|
+
environment:
|
|
52
|
+
- OLLAMA_BASE_URL=http://ollama:11434
|
|
53
|
+
- WEBUI_AUTH=${WEBUI_AUTH:-false}
|
|
54
|
+
depends_on:
|
|
55
|
+
ollama:
|
|
56
|
+
condition: service_healthy
|
|
57
|
+
|
|
58
|
+
# ── Optional: n8n (workflow automation) ───────────────────────────────────
|
|
59
|
+
n8n:
|
|
60
|
+
image: n8nio/n8n:latest
|
|
61
|
+
container_name: n8n
|
|
62
|
+
profiles: ["auto", "full"]
|
|
63
|
+
restart: unless-stopped
|
|
64
|
+
ports:
|
|
65
|
+
- "${N8N_PORT:-5678}:5678"
|
|
66
|
+
volumes:
|
|
67
|
+
- n8n_data:/home/node/.n8n
|
|
68
|
+
environment:
|
|
69
|
+
- N8N_SECURE_COOKIE=false
|
|
70
|
+
- OLLAMA_HOST=http://ollama:11434
|
|
71
|
+
|
|
72
|
+
# ── Optional: Supabase (Postgres + Auth + Realtime) ───────────────────────
|
|
73
|
+
supabase-db:
|
|
74
|
+
image: supabase/postgres:15.6.1.145
|
|
75
|
+
container_name: supabase-db
|
|
76
|
+
profiles: ["full"]
|
|
77
|
+
restart: unless-stopped
|
|
78
|
+
ports:
|
|
79
|
+
- "${SUPABASE_DB_PORT:-5432}:5432"
|
|
80
|
+
volumes:
|
|
81
|
+
- supabase_db_data:/var/lib/postgresql/data
|
|
82
|
+
environment:
|
|
83
|
+
POSTGRES_PASSWORD: ${SUPABASE_DB_PASSWORD:-postgres}
|
|
84
|
+
POSTGRES_DB: ${SUPABASE_DB_NAME:-app}
|
|
85
|
+
healthcheck:
|
|
86
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
87
|
+
interval: 10s
|
|
88
|
+
timeout: 5s
|
|
89
|
+
retries: 5
|
|
90
|
+
|
|
91
|
+
volumes:
|
|
92
|
+
ollama_data:
|
|
93
|
+
open_webui_data:
|
|
94
|
+
n8n_data:
|
|
95
|
+
supabase_db_data:
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/anthropics/claude-code/main/settings-schema.json",
|
|
3
|
+
"_comment": "Runtime security hooks (kiteguard-style) — scaffolded by javi-forge",
|
|
4
|
+
"hooks": {
|
|
5
|
+
"PreToolUse": [
|
|
6
|
+
{
|
|
7
|
+
"matcher": "Bash",
|
|
8
|
+
"hook": "COMMAND=\"$CLAUDE_TOOL_INPUT\"\nBLOCKED_PATTERNS=(\n 'rm -rf /'\n 'rm -rf ~'\n 'chmod 777'\n 'curl.*|.*sh'\n 'wget.*|.*sh'\n 'eval.*\\$'\n 'base64.*-d.*|.*sh'\n ':(){:|:&};:'\n)\nfor pattern in \"${BLOCKED_PATTERNS[@]}\"; do\n if echo \"$COMMAND\" | grep -qE \"$pattern\"; then\n echo \"BLOCKED: Dangerous command pattern detected: $pattern\"\n exit 2\n fi\ndone\nexit 0",
|
|
9
|
+
"description": "Block dangerous shell commands (rm -rf /, chmod 777, pipe-to-sh, fork bombs)"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"matcher": "Bash",
|
|
13
|
+
"hook": "COMMAND=\"$CLAUDE_TOOL_INPUT\"\nSENSITIVE_PATHS=(\n '.env'\n '.env.local'\n '.env.production'\n 'credentials'\n 'secrets'\n '.ssh'\n '.gnupg'\n '.aws/credentials'\n)\nfor path in \"${SENSITIVE_PATHS[@]}\"; do\n if echo \"$COMMAND\" | grep -qE \"(cat|less|head|tail|bat|read).*$path\"; then\n echo \"BLOCKED: Attempt to read sensitive file: $path\"\n exit 2\n fi\ndone\nexit 0",
|
|
14
|
+
"description": "Prevent reading sensitive files (.env, credentials, SSH keys)"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"matcher": "Write|Edit",
|
|
18
|
+
"hook": "INPUT=\"$CLAUDE_TOOL_INPUT\"\nPROTECTED_FILES=(\n '.env'\n '.env.production'\n 'credentials.json'\n 'serviceAccountKey.json'\n '.ssh/'\n '.gnupg/'\n)\nfor pf in \"${PROTECTED_FILES[@]}\"; do\n if echo \"$INPUT\" | grep -q \"$pf\"; then\n echo \"BLOCKED: Cannot modify protected file: $pf\"\n exit 2\n fi\ndone\nexit 0",
|
|
19
|
+
"description": "Prevent writing to credential and secret files"
|
|
20
|
+
}
|
|
21
|
+
],
|
|
22
|
+
"PostToolUse": [
|
|
23
|
+
{
|
|
24
|
+
"matcher": "Bash",
|
|
25
|
+
"hook": "OUTPUT=\"$CLAUDE_TOOL_OUTPUT\"\nLEAK_PATTERNS=(\n 'AKIA[0-9A-Z]{16}'\n 'ghp_[A-Za-z0-9]{36}'\n 'sk_live_[0-9a-zA-Z]{24,}'\n 'xox[baprs]-[0-9a-zA-Z-]+'\n '-----BEGIN.*PRIVATE KEY-----'\n)\nfor pattern in \"${LEAK_PATTERNS[@]}\"; do\n if echo \"$OUTPUT\" | grep -qE \"$pattern\"; then\n echo \"WARNING: Command output may contain secrets. Review carefully.\"\n exit 0\n fi\ndone\nexit 0",
|
|
26
|
+
"description": "Warn if command output contains potential secrets"
|
|
27
|
+
}
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# SECURITY LAYER 6: Commit Message Signing Reminder (commit-msg)
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Reminds developers to sign commits if signing is configured but the
|
|
6
|
+
# current commit is not signed. Non-blocking — just a nudge.
|
|
7
|
+
#
|
|
8
|
+
# This complements layer 4 (pre-push signing) with an earlier reminder.
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
YELLOW='\033[1;33m'
|
|
14
|
+
CYAN='\033[0;36m'
|
|
15
|
+
GREEN='\033[0;32m'
|
|
16
|
+
NC='\033[0m'
|
|
17
|
+
|
|
18
|
+
echo "SECURITY [6/6]: Commit signing reminder..."
|
|
19
|
+
|
|
20
|
+
GPG_SIGN=$(git config --get commit.gpgsign 2>/dev/null || echo "false")
|
|
21
|
+
|
|
22
|
+
if [ "$GPG_SIGN" = "true" ]; then
|
|
23
|
+
echo -e "${GREEN} Commit signing is enabled. Good.${NC}"
|
|
24
|
+
else
|
|
25
|
+
echo -e "${YELLOW} Tip: Enable commit signing for supply-chain security.${NC}"
|
|
26
|
+
echo -e "${CYAN} git config commit.gpgsign true${NC}"
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
exit 0
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# =============================================================================
|
|
3
|
+
# SECURITY LAYER 3: Permission Boundaries (pre-commit)
|
|
4
|
+
# =============================================================================
|
|
5
|
+
# Validates that staged files don't introduce overly permissive file modes,
|
|
6
|
+
# executable flags on non-script files, or world-writable permissions.
|
|
7
|
+
#
|
|
8
|
+
# To skip: git commit --no-verify (NOT recommended)
|
|
9
|
+
# =============================================================================
|
|
10
|
+
|
|
11
|
+
set -e
|
|
12
|
+
|
|
13
|
+
RED='\033[0;31m'
|
|
14
|
+
YELLOW='\033[1;33m'
|
|
15
|
+
GREEN='\033[0;32m'
|
|
16
|
+
NC='\033[0m'
|
|
17
|
+
|
|
18
|
+
echo "SECURITY [3/6]: Permission boundary check..."
|
|
19
|
+
|
|
20
|
+
STAGED_FILES=$(git diff --cached --name-only --diff-filter=ACM)
|
|
21
|
+
|
|
22
|
+
if [ -z "$STAGED_FILES" ]; then
|
|
23
|
+
echo -e "${GREEN} No staged files to check.${NC}"
|
|
24
|
+
exit 0
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
ISSUES=0
|
|
28
|
+
|
|
29
|
+
# Check for world-writable files (o+w)
|
|
30
|
+
for file in $STAGED_FILES; do
|
|
31
|
+
if [ -f "$file" ]; then
|
|
32
|
+
PERMS=$(stat -c '%a' "$file" 2>/dev/null || stat -f '%Lp' "$file" 2>/dev/null || echo "")
|
|
33
|
+
if [ -n "$PERMS" ]; then
|
|
34
|
+
# Check if last digit (other permissions) has write (2, 3, 6, 7)
|
|
35
|
+
OTHERS=${PERMS: -1}
|
|
36
|
+
if [[ "$OTHERS" =~ [2367] ]]; then
|
|
37
|
+
echo -e "${RED} World-writable: $file (mode $PERMS)${NC}"
|
|
38
|
+
ISSUES=$((ISSUES + 1))
|
|
39
|
+
fi
|
|
40
|
+
fi
|
|
41
|
+
fi
|
|
42
|
+
done
|
|
43
|
+
|
|
44
|
+
# Check for executable flag on non-script files
|
|
45
|
+
SCRIPT_EXTENSIONS='\.sh$|\.bash$|\.zsh$|\.py$|\.rb$|\.pl$'
|
|
46
|
+
for file in $STAGED_FILES; do
|
|
47
|
+
if [ -f "$file" ] && [ -x "$file" ]; then
|
|
48
|
+
# Allow scripts and hooks (no extension = likely a hook)
|
|
49
|
+
BASENAME=$(basename "$file")
|
|
50
|
+
if echo "$file" | grep -qE "$SCRIPT_EXTENSIONS"; then
|
|
51
|
+
continue
|
|
52
|
+
fi
|
|
53
|
+
# Allow files in hooks/ directories
|
|
54
|
+
if echo "$file" | grep -q '/hooks/'; then
|
|
55
|
+
continue
|
|
56
|
+
fi
|
|
57
|
+
# Allow if it has a shebang
|
|
58
|
+
if head -1 "$file" 2>/dev/null | grep -q '^#!'; then
|
|
59
|
+
continue
|
|
60
|
+
fi
|
|
61
|
+
echo -e "${YELLOW} Unexpected executable: $file${NC}"
|
|
62
|
+
ISSUES=$((ISSUES + 1))
|
|
63
|
+
fi
|
|
64
|
+
done
|
|
65
|
+
|
|
66
|
+
if [ "$ISSUES" -gt 0 ]; then
|
|
67
|
+
echo -e ""
|
|
68
|
+
echo -e "${RED}COMMIT BLOCKED: $ISSUES permission issue(s) found.${NC}"
|
|
69
|
+
echo -e "${YELLOW} Fix file permissions before committing.${NC}"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
echo -e "${GREEN} Permissions OK.${NC}"
|
|
74
|
+
exit 0
|