@sk8metal/michi-cli 0.4.0 → 0.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/CHANGELOG.md +162 -1
- package/README.md +2 -1
- package/dist/scripts/config/config-schema.d.ts +87 -0
- package/dist/scripts/config/config-schema.d.ts.map +1 -1
- package/dist/scripts/config/config-schema.js +81 -0
- package/dist/scripts/config/config-schema.js.map +1 -1
- package/dist/scripts/confluence-sync.d.ts.map +1 -1
- package/dist/scripts/confluence-sync.js +15 -2
- package/dist/scripts/confluence-sync.js.map +1 -1
- package/dist/scripts/github-actions-client.d.ts +79 -0
- package/dist/scripts/github-actions-client.d.ts.map +1 -0
- package/dist/scripts/github-actions-client.js +182 -0
- package/dist/scripts/github-actions-client.js.map +1 -0
- package/dist/scripts/health-check-service.d.ts +46 -0
- package/dist/scripts/health-check-service.d.ts.map +1 -0
- package/dist/scripts/health-check-service.js +114 -0
- package/dist/scripts/health-check-service.js.map +1 -0
- package/dist/scripts/markdown-to-confluence.d.ts.map +1 -1
- package/dist/scripts/markdown-to-confluence.js +25 -3
- package/dist/scripts/markdown-to-confluence.js.map +1 -1
- package/dist/scripts/mermaid-converter.d.ts +24 -0
- package/dist/scripts/mermaid-converter.d.ts.map +1 -0
- package/dist/scripts/mermaid-converter.js +49 -0
- package/dist/scripts/mermaid-converter.js.map +1 -0
- package/dist/scripts/pr-automation.d.ts.map +1 -1
- package/dist/scripts/pr-automation.js +11 -3
- package/dist/scripts/pr-automation.js.map +1 -1
- package/dist/scripts/spec-impl-workflow.d.ts.map +1 -1
- package/dist/scripts/spec-impl-workflow.js +22 -6
- package/dist/scripts/spec-impl-workflow.js.map +1 -1
- package/dist/scripts/template/multi-repo-renderer.d.ts +67 -0
- package/dist/scripts/template/multi-repo-renderer.d.ts.map +1 -0
- package/dist/scripts/template/multi-repo-renderer.js +123 -0
- package/dist/scripts/template/multi-repo-renderer.js.map +1 -0
- package/dist/scripts/template/renderer.d.ts +4 -0
- package/dist/scripts/template/renderer.d.ts.map +1 -1
- package/dist/scripts/template/renderer.js.map +1 -1
- package/dist/scripts/test-execution-generator.d.ts.map +1 -1
- package/dist/scripts/test-execution-generator.js +94 -11
- package/dist/scripts/test-execution-generator.js.map +1 -1
- package/dist/scripts/test-script-runner.d.ts +33 -0
- package/dist/scripts/test-script-runner.d.ts.map +1 -0
- package/dist/scripts/test-script-runner.js +77 -0
- package/dist/scripts/test-script-runner.js.map +1 -0
- package/dist/scripts/utils/config-loader.d.ts +31 -5
- package/dist/scripts/utils/config-loader.d.ts.map +1 -1
- package/dist/scripts/utils/config-loader.js +363 -50
- package/dist/scripts/utils/config-loader.js.map +1 -1
- package/dist/scripts/utils/env-config.d.ts +1 -1
- package/dist/scripts/utils/env-config.d.ts.map +1 -1
- package/dist/scripts/utils/env-config.js +2 -14
- package/dist/scripts/utils/env-config.js.map +1 -1
- package/dist/scripts/utils/multi-repo-validator.d.ts +30 -0
- package/dist/scripts/utils/multi-repo-validator.d.ts.map +1 -0
- package/dist/scripts/utils/multi-repo-validator.js +105 -0
- package/dist/scripts/utils/multi-repo-validator.js.map +1 -0
- package/dist/scripts/utils/project-meta.d.ts +9 -0
- package/dist/scripts/utils/project-meta.d.ts.map +1 -1
- package/dist/scripts/utils/project-meta.js +22 -0
- package/dist/scripts/utils/project-meta.js.map +1 -1
- package/dist/scripts/utils/security-validator.d.ts +55 -0
- package/dist/scripts/utils/security-validator.d.ts.map +1 -0
- package/dist/scripts/utils/security-validator.js +232 -0
- package/dist/scripts/utils/security-validator.js.map +1 -0
- package/dist/scripts/utils/spec-archiver.d.ts +38 -0
- package/dist/scripts/utils/spec-archiver.d.ts.map +1 -0
- package/dist/scripts/utils/spec-archiver.js +210 -0
- package/dist/scripts/utils/spec-archiver.js.map +1 -0
- package/dist/scripts/utils/spec-updater.d.ts +4 -0
- package/dist/scripts/utils/spec-updater.d.ts.map +1 -1
- package/dist/scripts/utils/spec-updater.js.map +1 -1
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +303 -17
- package/dist/src/cli.js.map +1 -1
- package/dist/src/commands/config-validate.d.ts +9 -0
- package/dist/src/commands/config-validate.d.ts.map +1 -0
- package/dist/src/commands/config-validate.js +90 -0
- package/dist/src/commands/config-validate.js.map +1 -0
- package/dist/src/commands/init.d.ts +1 -0
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +29 -6
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/migrate.d.ts +25 -0
- package/dist/src/commands/migrate.d.ts.map +1 -0
- package/dist/src/commands/migrate.js +341 -0
- package/dist/src/commands/migrate.js.map +1 -0
- package/dist/src/commands/multi-repo-add-repo.d.ts +26 -0
- package/dist/src/commands/multi-repo-add-repo.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-add-repo.js +56 -0
- package/dist/src/commands/multi-repo-add-repo.js.map +1 -0
- package/dist/src/commands/multi-repo-ci-status.d.ts +46 -0
- package/dist/src/commands/multi-repo-ci-status.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-ci-status.js +285 -0
- package/dist/src/commands/multi-repo-ci-status.js.map +1 -0
- package/dist/src/commands/multi-repo-confluence-sync.d.ts +45 -0
- package/dist/src/commands/multi-repo-confluence-sync.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-confluence-sync.js +135 -0
- package/dist/src/commands/multi-repo-confluence-sync.js.map +1 -0
- package/dist/src/commands/multi-repo-init.d.ts +26 -0
- package/dist/src/commands/multi-repo-init.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-init.js +101 -0
- package/dist/src/commands/multi-repo-init.js.map +1 -0
- package/dist/src/commands/multi-repo-list.d.ts +28 -0
- package/dist/src/commands/multi-repo-list.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-list.js +38 -0
- package/dist/src/commands/multi-repo-list.js.map +1 -0
- package/dist/src/commands/multi-repo-test.d.ts +56 -0
- package/dist/src/commands/multi-repo-test.d.ts.map +1 -0
- package/dist/src/commands/multi-repo-test.js +70 -0
- package/dist/src/commands/multi-repo-test.js.map +1 -0
- package/dist/src/commands/setup-existing.d.ts.map +1 -1
- package/dist/src/commands/setup-existing.js +0 -1
- package/dist/src/commands/setup-existing.js.map +1 -1
- package/dist/src/commands/spec-archive.d.ts +17 -0
- package/dist/src/commands/spec-archive.d.ts.map +1 -0
- package/dist/src/commands/spec-archive.js +40 -0
- package/dist/src/commands/spec-archive.js.map +1 -0
- package/dist/src/commands/spec-list.d.ts +15 -0
- package/dist/src/commands/spec-list.d.ts.map +1 -0
- package/dist/src/commands/spec-list.js +55 -0
- package/dist/src/commands/spec-list.js.map +1 -0
- package/dist/vitest.config.d.ts.map +1 -1
- package/dist/vitest.config.js +32 -8
- package/dist/vitest.config.js.map +1 -1
- package/docs/michi-development/design/config-unification.md +4789 -0
- package/docs/user-guide/getting-started/github-token-setup.md +2 -1
- package/docs/user-guide/getting-started/new-repository-setup.md +1 -1
- package/docs/user-guide/getting-started/quick-start.md +1 -1
- package/docs/user-guide/getting-started/setup.md +4 -11
- package/docs/user-guide/guides/multi-repo-guide.md +591 -0
- package/docs/user-guide/guides/multi-repo-migration-guide.md +516 -0
- package/docs/user-guide/hands-on/claude-agent-setup.md +2 -2
- package/docs/user-guide/hands-on/claude-setup.md +2 -2
- package/docs/user-guide/hands-on/cursor-setup.md +2 -2
- package/docs/user-guide/hands-on/workflow-walkthrough.md +4 -1
- package/docs/user-guide/reference/multi-repo-api.md +771 -0
- package/docs/user-guide/reference/quick-reference.md +22 -37
- package/env.example +1 -1
- package/package.json +2 -5
- package/scripts/__tests__/config-loader-multi-repo.test.ts +342 -0
- package/scripts/__tests__/github-actions-client.test.ts +543 -0
- package/scripts/__tests__/health-check-service.test.ts +142 -0
- package/scripts/__tests__/markdown-to-confluence.test.ts +262 -0
- package/scripts/__tests__/mermaid-converter.test.ts +236 -0
- package/scripts/__tests__/multi-repo-config-schema.test.ts +335 -0
- package/scripts/__tests__/multi-repo-validator.test.ts +524 -0
- package/scripts/__tests__/spec-archiver.test.ts +512 -0
- package/scripts/__tests__/spec-impl-workflow.test.ts +5 -2
- package/scripts/__tests__/test-script-runner.test.ts +217 -0
- package/scripts/config/config-schema.ts +104 -0
- package/scripts/confluence-sync.ts +16 -2
- package/scripts/github-actions-client.ts +258 -0
- package/scripts/health-check-service.ts +171 -0
- package/scripts/markdown-to-confluence.ts +37 -6
- package/scripts/mermaid-converter.ts +56 -0
- package/scripts/pr-automation.ts +15 -5
- package/scripts/spec-impl-workflow.ts +22 -6
- package/scripts/template/__tests__/multi-repo-renderer.test.ts +261 -0
- package/scripts/template/multi-repo-renderer.ts +172 -0
- package/scripts/template/renderer.ts +5 -0
- package/scripts/test-execution-generator.ts +104 -11
- package/scripts/test-script-runner.ts +130 -0
- package/scripts/utils/__tests__/config-loader.test.ts +149 -0
- package/scripts/utils/__tests__/config-validator.test.ts +106 -6
- package/scripts/utils/__tests__/env-config.test.ts +0 -2
- package/scripts/utils/__tests__/multi-repo-validator.test.ts +335 -0
- package/scripts/utils/__tests__/project-meta.test.ts +192 -0
- package/scripts/utils/__tests__/security-validator.test.ts +272 -0
- package/scripts/utils/config-loader.ts +429 -56
- package/scripts/utils/env-config.ts +2 -14
- package/scripts/utils/multi-repo-validator.ts +141 -0
- package/scripts/utils/project-meta.ts +27 -0
- package/scripts/utils/security-validator.ts +286 -0
- package/scripts/utils/spec-archiver.ts +260 -0
- package/scripts/utils/spec-updater.ts +4 -0
- package/templates/claude/agents/pr-size-monitor/AGENT.md +330 -0
- package/templates/claude/commands/kiro/kiro-spec-impl.md +1 -1
- package/templates/claude/commands/michi/spec-impl.md +208 -35
- package/templates/claude-agent/commands/kiro/kiro-spec-impl.md +1 -1
- package/templates/cursor/commands/kiro/kiro-spec-impl.md +1 -1
- package/templates/multi-repo/docs/ci-status.md +51 -0
- package/templates/multi-repo/docs/release-notes.md +99 -0
- package/templates/multi-repo/overview/architecture.md +102 -0
- package/templates/multi-repo/overview/requirements.md +68 -0
- package/templates/multi-repo/overview/sequence.md +79 -0
- package/templates/multi-repo/steering/multi-repo.md +74 -0
- package/templates/multi-repo/tests/strategy.md +89 -0
- package/dist/scripts/__tests__/create-project.test.d.ts +0 -2
- package/dist/scripts/__tests__/create-project.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/create-project.test.js +0 -243
- package/dist/scripts/__tests__/create-project.test.js.map +0 -1
- package/dist/scripts/__tests__/jira-transitions.test.d.ts +0 -5
- package/dist/scripts/__tests__/jira-transitions.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/jira-transitions.test.js +0 -172
- package/dist/scripts/__tests__/jira-transitions.test.js.map +0 -1
- package/dist/scripts/__tests__/multi-project-estimate.test.d.ts +0 -2
- package/dist/scripts/__tests__/multi-project-estimate.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/multi-project-estimate.test.js +0 -118
- package/dist/scripts/__tests__/multi-project-estimate.test.js.map +0 -1
- package/dist/scripts/__tests__/setup-existing-project.test.d.ts +0 -2
- package/dist/scripts/__tests__/setup-existing-project.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/setup-existing-project.test.js +0 -208
- package/dist/scripts/__tests__/setup-existing-project.test.js.map +0 -1
- package/dist/scripts/__tests__/setup-interactive.test.d.ts +0 -2
- package/dist/scripts/__tests__/setup-interactive.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/setup-interactive.test.js +0 -166
- package/dist/scripts/__tests__/setup-interactive.test.js.map +0 -1
- package/dist/scripts/__tests__/spec-impl-workflow.test.d.ts +0 -5
- package/dist/scripts/__tests__/spec-impl-workflow.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/spec-impl-workflow.test.js +0 -321
- package/dist/scripts/__tests__/spec-impl-workflow.test.js.map +0 -1
- package/dist/scripts/__tests__/spec-loader.test.d.ts +0 -5
- package/dist/scripts/__tests__/spec-loader.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/spec-loader.test.js +0 -153
- package/dist/scripts/__tests__/spec-loader.test.js.map +0 -1
- package/dist/scripts/__tests__/validate-phase.test.d.ts +0 -5
- package/dist/scripts/__tests__/validate-phase.test.d.ts.map +0 -1
- package/dist/scripts/__tests__/validate-phase.test.js +0 -249
- package/dist/scripts/__tests__/validate-phase.test.js.map +0 -1
- package/dist/scripts/constants/__tests__/environments.test.d.ts +0 -2
- package/dist/scripts/constants/__tests__/environments.test.d.ts.map +0 -1
- package/dist/scripts/constants/__tests__/environments.test.js +0 -125
- package/dist/scripts/constants/__tests__/environments.test.js.map +0 -1
- package/dist/scripts/constants/__tests__/languages.test.d.ts +0 -2
- package/dist/scripts/constants/__tests__/languages.test.d.ts.map +0 -1
- package/dist/scripts/constants/__tests__/languages.test.js +0 -82
- package/dist/scripts/constants/__tests__/languages.test.js.map +0 -1
- package/dist/scripts/create-project.d.ts +0 -16
- package/dist/scripts/create-project.d.ts.map +0 -1
- package/dist/scripts/create-project.js +0 -334
- package/dist/scripts/create-project.js.map +0 -1
- package/dist/scripts/list-projects.d.ts +0 -7
- package/dist/scripts/list-projects.d.ts.map +0 -1
- package/dist/scripts/list-projects.js +0 -88
- package/dist/scripts/list-projects.js.map +0 -1
- package/dist/scripts/template/__tests__/renderer.test.d.ts +0 -2
- package/dist/scripts/template/__tests__/renderer.test.d.ts.map +0 -1
- package/dist/scripts/template/__tests__/renderer.test.js +0 -165
- package/dist/scripts/template/__tests__/renderer.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/aidlc-parser.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/aidlc-parser.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/aidlc-parser.test.js +0 -315
- package/dist/scripts/utils/__tests__/aidlc-parser.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/business-days.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/business-days.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/business-days.test.js +0 -171
- package/dist/scripts/utils/__tests__/business-days.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/config-loader.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/config-loader.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/config-loader.test.js +0 -201
- package/dist/scripts/utils/__tests__/config-loader.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/config-validator.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/config-validator.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/config-validator.test.js +0 -394
- package/dist/scripts/utils/__tests__/config-validator.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/env-config.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/env-config.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/env-config.test.js +0 -218
- package/dist/scripts/utils/__tests__/env-config.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/feature-name-validator.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/feature-name-validator.test.js +0 -106
- package/dist/scripts/utils/__tests__/feature-name-validator.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.js +0 -202
- package/dist/scripts/utils/__tests__/jira-issue-type-fetcher.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/spec-updater.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/spec-updater.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/spec-updater.test.js +0 -158
- package/dist/scripts/utils/__tests__/spec-updater.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-converter.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/tasks-converter.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-converter.test.js +0 -500
- package/dist/scripts/utils/__tests__/tasks-converter.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.js +0 -314
- package/dist/scripts/utils/__tests__/tasks-format-validator.test.js.map +0 -1
- package/dist/scripts/utils/__tests__/test-runner.test.d.ts +0 -5
- package/dist/scripts/utils/__tests__/test-runner.test.d.ts.map +0 -1
- package/dist/scripts/utils/__tests__/test-runner.test.js +0 -64
- package/dist/scripts/utils/__tests__/test-runner.test.js.map +0 -1
- package/dist/src/__tests__/cli.test.d.ts +0 -5
- package/dist/src/__tests__/cli.test.d.ts.map +0 -1
- package/dist/src/__tests__/cli.test.js +0 -58
- package/dist/src/__tests__/cli.test.js.map +0 -1
- package/dist/src/__tests__/integration/internationalization.test.d.ts +0 -8
- package/dist/src/__tests__/integration/internationalization.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/internationalization.test.js +0 -333
- package/dist/src/__tests__/integration/internationalization.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/claude-agent.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/claude-agent.test.js +0 -122
- package/dist/src/__tests__/integration/setup/claude-agent.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/claude.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/claude.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/claude.test.js +0 -193
- package/dist/src/__tests__/integration/setup/claude.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/cursor.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/cursor.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/cursor.test.js +0 -166
- package/dist/src/__tests__/integration/setup/cursor.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts +0 -32
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js +0 -72
- package/dist/src/__tests__/integration/setup/helpers/fs-assertions.js.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts +0 -38
- package/dist/src/__tests__/integration/setup/helpers/test-project.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/helpers/test-project.js +0 -83
- package/dist/src/__tests__/integration/setup/helpers/test-project.js.map +0 -1
- package/dist/src/__tests__/integration/setup/init.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/init.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/init.test.js +0 -352
- package/dist/src/__tests__/integration/setup/init.test.js.map +0 -1
- package/dist/src/__tests__/integration/setup/validation.test.d.ts +0 -5
- package/dist/src/__tests__/integration/setup/validation.test.d.ts.map +0 -1
- package/dist/src/__tests__/integration/setup/validation.test.js +0 -301
- package/dist/src/__tests__/integration/setup/validation.test.js.map +0 -1
- package/scripts/create-project.ts +0 -386
- package/scripts/list-projects.ts +0 -112
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* multi-repo-validator.ts
|
|
3
|
+
* Multi-Repo機能のバリデーションユーティリティ
|
|
4
|
+
*
|
|
5
|
+
* プロジェクト名、JIRAキー、リポジトリURLのバリデーションとセキュリティチェックを行います。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* バリデーション結果
|
|
10
|
+
*/
|
|
11
|
+
export interface ValidationResult {
|
|
12
|
+
isValid: boolean;
|
|
13
|
+
errors: string[];
|
|
14
|
+
warnings: string[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* プロジェクト名のバリデーション
|
|
19
|
+
* セキュリティ対策: パストラバーサル、相対パス、制御文字をチェック
|
|
20
|
+
*/
|
|
21
|
+
export function validateProjectName(name: string): ValidationResult {
|
|
22
|
+
const errors: string[] = [];
|
|
23
|
+
const warnings: string[] = [];
|
|
24
|
+
|
|
25
|
+
// 長さチェック: 1-100文字
|
|
26
|
+
if (name.length < 1 || name.length > 100) {
|
|
27
|
+
errors.push('Project name must be between 1 and 100 characters');
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// パストラバーサル対策: '/', '\' 禁止
|
|
31
|
+
if (name.includes('/') || name.includes('\\')) {
|
|
32
|
+
errors.push(
|
|
33
|
+
'Project name must not contain path traversal characters (/, \\)',
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// 相対パス対策: '.', '..' 禁止
|
|
38
|
+
if (name === '.' || name === '..') {
|
|
39
|
+
errors.push(
|
|
40
|
+
'Project name must not be relative path components (., ..)',
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// 制御文字対策: \x00-\x1F, \x7F 禁止
|
|
45
|
+
// eslint-disable-next-line no-control-regex
|
|
46
|
+
const controlCharRegex = /[\x00-\x1F\x7F]/;
|
|
47
|
+
if (controlCharRegex.test(name)) {
|
|
48
|
+
errors.push('Project name must not contain control characters');
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
isValid: errors.length === 0,
|
|
53
|
+
errors,
|
|
54
|
+
warnings,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* JIRAキーのバリデーション
|
|
60
|
+
* 2-10文字の大文字英字のみ許可
|
|
61
|
+
*/
|
|
62
|
+
export function validateJiraKey(key: string): ValidationResult {
|
|
63
|
+
const errors: string[] = [];
|
|
64
|
+
const warnings: string[] = [];
|
|
65
|
+
|
|
66
|
+
// 正規表現: 2-10文字の大文字英字
|
|
67
|
+
const jiraKeyRegex = /^[A-Z]{2,10}$/;
|
|
68
|
+
|
|
69
|
+
if (!jiraKeyRegex.test(key)) {
|
|
70
|
+
errors.push('JIRA key must be 2-10 uppercase letters');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return {
|
|
74
|
+
isValid: errors.length === 0,
|
|
75
|
+
errors,
|
|
76
|
+
warnings,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* リポジトリURLのバリデーション
|
|
82
|
+
* GitHub HTTPS URL形式のみ許可
|
|
83
|
+
*/
|
|
84
|
+
export function validateRepositoryUrl(url: string): ValidationResult {
|
|
85
|
+
const errors: string[] = [];
|
|
86
|
+
const warnings: string[] = [];
|
|
87
|
+
|
|
88
|
+
// 空文字列チェック
|
|
89
|
+
if (!url || url.trim() === '') {
|
|
90
|
+
errors.push('Repository URL is empty');
|
|
91
|
+
return { isValid: false, errors, warnings };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// SSH URL検出(git@github.com:形式)
|
|
95
|
+
if (url.startsWith('git@')) {
|
|
96
|
+
errors.push(
|
|
97
|
+
'Repository URL must be in GitHub format: https://github.com/{owner}/{repo}',
|
|
98
|
+
);
|
|
99
|
+
return { isValid: false, errors, warnings };
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// URL形式チェック
|
|
103
|
+
try {
|
|
104
|
+
const parsedUrl = new URL(url);
|
|
105
|
+
|
|
106
|
+
// HTTPSプロトコルチェック
|
|
107
|
+
if (parsedUrl.protocol !== 'https:') {
|
|
108
|
+
errors.push('Repository URL must use HTTPS protocol');
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// GitHub URL形式チェック: https://github.com/{owner}/{repo}
|
|
112
|
+
const githubPattern = /^https:\/\/github\.com\/[^/]+\/[^/]+$/;
|
|
113
|
+
if (!githubPattern.test(url)) {
|
|
114
|
+
errors.push(
|
|
115
|
+
'Repository URL must be in GitHub format: https://github.com/{owner}/{repo}',
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// .git拡張子チェック
|
|
120
|
+
if (url.endsWith('.git')) {
|
|
121
|
+
errors.push('Repository URL must not include .git extension');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// プレースホルダー検出
|
|
125
|
+
if (
|
|
126
|
+
url.includes('your-org') ||
|
|
127
|
+
url.includes('your-repo') ||
|
|
128
|
+
url.includes('repo-name')
|
|
129
|
+
) {
|
|
130
|
+
errors.push('Repository URL contains placeholder values');
|
|
131
|
+
}
|
|
132
|
+
} catch (_error) {
|
|
133
|
+
errors.push('Repository URL format is invalid');
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return {
|
|
137
|
+
isValid: errors.length === 0,
|
|
138
|
+
errors,
|
|
139
|
+
warnings,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
@@ -67,3 +67,30 @@ Team: ${meta.team.join(', ')}
|
|
|
67
67
|
`.trim();
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* GitHub リポジトリ情報を取得
|
|
72
|
+
* repository フィールドから owner/repo 形式を抽出
|
|
73
|
+
*
|
|
74
|
+
* @param projectRoot プロジェクトルートディレクトリ(デフォルト: カレントディレクトリ)
|
|
75
|
+
* @returns owner/repo 形式のリポジトリ情報
|
|
76
|
+
* @throws リポジトリ情報が見つからない、または無効な形式の場合
|
|
77
|
+
*/
|
|
78
|
+
export function getRepositoryInfo(projectRoot: string = process.cwd()): string {
|
|
79
|
+
const meta = loadProjectMeta(projectRoot);
|
|
80
|
+
|
|
81
|
+
if (!meta.repository) {
|
|
82
|
+
throw new Error('Repository information not found in project.json');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// URL形式から owner/repo を抽出
|
|
86
|
+
// 例: https://github.com/owner/repo.git -> owner/repo
|
|
87
|
+
// 例: git@github.com:owner/repo.git -> owner/repo
|
|
88
|
+
const match = meta.repository.match(/github\.com[:/]([\w-]+\/[\w-]+)(\.git)?/);
|
|
89
|
+
|
|
90
|
+
if (!match) {
|
|
91
|
+
throw new Error(`Invalid GitHub repository format: ${meta.repository}`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return match[1];
|
|
95
|
+
}
|
|
96
|
+
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* security-validator.ts
|
|
3
|
+
* セキュリティ検証ユーティリティ
|
|
4
|
+
*
|
|
5
|
+
* 環境変数やAPIトークンなど機密情報のバリデーションとセキュリティチェックを行います。
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { statSync } from 'fs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* バリデーション結果
|
|
12
|
+
*/
|
|
13
|
+
export interface ValidationResult {
|
|
14
|
+
isValid: boolean;
|
|
15
|
+
errors: string[];
|
|
16
|
+
warnings: string[];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* APIトークン形式の検証
|
|
21
|
+
*/
|
|
22
|
+
export function validateAtlassianToken(token: string): ValidationResult {
|
|
23
|
+
const errors: string[] = [];
|
|
24
|
+
const warnings: string[] = [];
|
|
25
|
+
|
|
26
|
+
if (!token || token.trim() === '') {
|
|
27
|
+
errors.push('Atlassian API token is empty');
|
|
28
|
+
return { isValid: false, errors, warnings };
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (token.includes(' ')) {
|
|
32
|
+
errors.push('Atlassian API token contains spaces');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
if (token === 'your-token-here' || token === 'test-token' || token === 'token123') {
|
|
36
|
+
errors.push('Atlassian API token is a placeholder value');
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (token.length < 20) {
|
|
40
|
+
warnings.push('Atlassian API token seems too short (expected >20 characters)');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return {
|
|
44
|
+
isValid: errors.length === 0,
|
|
45
|
+
errors,
|
|
46
|
+
warnings,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* GitHub Personal Access Token の検証
|
|
52
|
+
*/
|
|
53
|
+
export function validateGitHubToken(token: string): ValidationResult {
|
|
54
|
+
const errors: string[] = [];
|
|
55
|
+
const warnings: string[] = [];
|
|
56
|
+
|
|
57
|
+
if (!token || token.trim() === '') {
|
|
58
|
+
errors.push('GitHub token is empty');
|
|
59
|
+
} else if (token.includes(' ')) {
|
|
60
|
+
errors.push('GitHub token contains spaces');
|
|
61
|
+
} else if (!token.startsWith('ghp_') && !token.startsWith('github_pat_')) {
|
|
62
|
+
warnings.push('GitHub token does not start with expected prefix (ghp_ or github_pat_)');
|
|
63
|
+
} else if (token === 'ghp_xxx' || token === 'your-github-token' || token === 'github-token') {
|
|
64
|
+
errors.push('GitHub token is a placeholder value');
|
|
65
|
+
} else if (token.length < 30) {
|
|
66
|
+
warnings.push('GitHub token seems too short');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return {
|
|
70
|
+
isValid: errors.length === 0,
|
|
71
|
+
errors,
|
|
72
|
+
warnings,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* メールアドレス形式の検証
|
|
78
|
+
*/
|
|
79
|
+
export function validateEmail(email: string): ValidationResult {
|
|
80
|
+
const errors: string[] = [];
|
|
81
|
+
const warnings: string[] = [];
|
|
82
|
+
|
|
83
|
+
if (!email || email.trim() === '') {
|
|
84
|
+
errors.push('Email is empty');
|
|
85
|
+
} else {
|
|
86
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
87
|
+
if (!emailRegex.test(email)) {
|
|
88
|
+
errors.push('Email format is invalid');
|
|
89
|
+
} else if (
|
|
90
|
+
email === 'user@example.com' ||
|
|
91
|
+
email.includes('your-email') ||
|
|
92
|
+
email === 'test@example.com'
|
|
93
|
+
) {
|
|
94
|
+
errors.push('Email is a placeholder value');
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
isValid: errors.length === 0,
|
|
100
|
+
errors,
|
|
101
|
+
warnings,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* URL形式の検証
|
|
107
|
+
*/
|
|
108
|
+
export function validateUrl(url: string, expectedDomain?: string): ValidationResult {
|
|
109
|
+
const errors: string[] = [];
|
|
110
|
+
const warnings: string[] = [];
|
|
111
|
+
|
|
112
|
+
if (!url || url.trim() === '') {
|
|
113
|
+
errors.push('URL is empty');
|
|
114
|
+
} else {
|
|
115
|
+
try {
|
|
116
|
+
const parsedUrl = new URL(url);
|
|
117
|
+
|
|
118
|
+
if (parsedUrl.protocol !== 'https:' && parsedUrl.protocol !== 'http:') {
|
|
119
|
+
errors.push(`Invalid URL protocol: ${parsedUrl.protocol} (expected https: or http:)`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (parsedUrl.protocol === 'http:') {
|
|
123
|
+
warnings.push('URL uses insecure http:// protocol (consider using https://)');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (expectedDomain && !parsedUrl.hostname.includes(expectedDomain)) {
|
|
127
|
+
errors.push(`URL hostname ${parsedUrl.hostname} does not contain expected domain: ${expectedDomain}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (url === 'https://example.com' || url === 'https://your-domain.atlassian.net') {
|
|
131
|
+
errors.push('URL is a placeholder value');
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
errors.push(`URL parsing failed: ${error instanceof Error ? error.message : error}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return {
|
|
139
|
+
isValid: errors.length === 0,
|
|
140
|
+
errors,
|
|
141
|
+
warnings,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Atlassian URL の検証
|
|
147
|
+
*/
|
|
148
|
+
export function validateAtlassianUrl(url: string): ValidationResult {
|
|
149
|
+
const result = validateUrl(url, 'atlassian.net');
|
|
150
|
+
|
|
151
|
+
if (result.isValid) {
|
|
152
|
+
try {
|
|
153
|
+
const parsedUrl = new URL(url);
|
|
154
|
+
if (!parsedUrl.hostname.endsWith('.atlassian.net')) {
|
|
155
|
+
result.errors.push('Atlassian URL must end with .atlassian.net');
|
|
156
|
+
result.isValid = false;
|
|
157
|
+
}
|
|
158
|
+
} catch {
|
|
159
|
+
// Already handled in validateUrl
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return result;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* GitHub リポジトリ URL の検証
|
|
168
|
+
*/
|
|
169
|
+
export function validateGitHubRepositoryUrl(url: string): ValidationResult {
|
|
170
|
+
const errors: string[] = [];
|
|
171
|
+
const warnings: string[] = [];
|
|
172
|
+
|
|
173
|
+
if (!url || url.trim() === '') {
|
|
174
|
+
errors.push('Repository URL is empty');
|
|
175
|
+
} else {
|
|
176
|
+
// GitHub URL 形式のパターン
|
|
177
|
+
const httpsPattern = /^https:\/\/github\.com\/[\w-]+\/[\w-]+(\.git)?$/;
|
|
178
|
+
const sshPattern = /^git@github\.com:[\w-]+\/[\w-]+(\.git)?$/;
|
|
179
|
+
|
|
180
|
+
if (!httpsPattern.test(url) && !sshPattern.test(url)) {
|
|
181
|
+
errors.push(
|
|
182
|
+
'Repository URL must be in format: https://github.com/owner/repo.git or git@github.com:owner/repo.git',
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (url.includes('your-org') || url.includes('your-repo')) {
|
|
187
|
+
errors.push('Repository URL contains placeholder values');
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
isValid: errors.length === 0,
|
|
193
|
+
errors,
|
|
194
|
+
warnings,
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* 環境変数の包括的検証
|
|
200
|
+
*/
|
|
201
|
+
export interface EnvValidationConfig {
|
|
202
|
+
atlassianUrl?: string;
|
|
203
|
+
atlassianEmail?: string;
|
|
204
|
+
atlassianApiToken?: string;
|
|
205
|
+
githubOrg?: string;
|
|
206
|
+
githubToken?: string;
|
|
207
|
+
repositoryUrl?: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export function validateEnvironmentConfig(config: EnvValidationConfig): ValidationResult {
|
|
211
|
+
const allErrors: string[] = [];
|
|
212
|
+
const allWarnings: string[] = [];
|
|
213
|
+
|
|
214
|
+
if (config.atlassianUrl !== undefined) {
|
|
215
|
+
const result = validateAtlassianUrl(config.atlassianUrl);
|
|
216
|
+
allErrors.push(...result.errors.map((e) => `ATLASSIAN_URL: ${e}`));
|
|
217
|
+
allWarnings.push(...result.warnings.map((w) => `ATLASSIAN_URL: ${w}`));
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
if (config.atlassianEmail !== undefined) {
|
|
221
|
+
const result = validateEmail(config.atlassianEmail);
|
|
222
|
+
allErrors.push(...result.errors.map((e) => `ATLASSIAN_EMAIL: ${e}`));
|
|
223
|
+
allWarnings.push(...result.warnings.map((w) => `ATLASSIAN_EMAIL: ${w}`));
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
if (config.atlassianApiToken !== undefined) {
|
|
227
|
+
const result = validateAtlassianToken(config.atlassianApiToken);
|
|
228
|
+
allErrors.push(...result.errors.map((e) => `ATLASSIAN_API_TOKEN: ${e}`));
|
|
229
|
+
allWarnings.push(...result.warnings.map((w) => `ATLASSIAN_API_TOKEN: ${w}`));
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (config.githubOrg !== undefined) {
|
|
233
|
+
if (!config.githubOrg || config.githubOrg.trim() === '') {
|
|
234
|
+
allErrors.push('GITHUB_ORG: GitHub organization is empty');
|
|
235
|
+
} else if (config.githubOrg.includes('your-org')) {
|
|
236
|
+
allErrors.push('GITHUB_ORG: GitHub organization is a placeholder value');
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (config.githubToken !== undefined) {
|
|
241
|
+
const result = validateGitHubToken(config.githubToken);
|
|
242
|
+
allErrors.push(...result.errors.map((e) => `GITHUB_TOKEN: ${e}`));
|
|
243
|
+
allWarnings.push(...result.warnings.map((w) => `GITHUB_TOKEN: ${w}`));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if (config.repositoryUrl !== undefined) {
|
|
247
|
+
const result = validateGitHubRepositoryUrl(config.repositoryUrl);
|
|
248
|
+
allErrors.push(...result.errors.map((e) => `repository: ${e}`));
|
|
249
|
+
allWarnings.push(...result.warnings.map((w) => `repository: ${w}`));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
isValid: allErrors.length === 0,
|
|
254
|
+
errors: allErrors,
|
|
255
|
+
warnings: allWarnings,
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* ファイルパーミッションの検証(Unix系のみ)
|
|
261
|
+
*/
|
|
262
|
+
export function validateFilePermissions(filePath: string, expectedMode: number = 0o600): ValidationResult {
|
|
263
|
+
const errors: string[] = [];
|
|
264
|
+
const warnings: string[] = [];
|
|
265
|
+
|
|
266
|
+
try {
|
|
267
|
+
const stats = statSync(filePath);
|
|
268
|
+
const actualMode = stats.mode & 0o777;
|
|
269
|
+
|
|
270
|
+
if (actualMode !== expectedMode) {
|
|
271
|
+
const actualOctal = actualMode.toString(8);
|
|
272
|
+
const expectedOctal = expectedMode.toString(8);
|
|
273
|
+
warnings.push(
|
|
274
|
+
`File permissions are ${actualOctal} but should be ${expectedOctal} for security. Run: chmod ${expectedOctal} ${filePath}`,
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
} catch (error) {
|
|
278
|
+
errors.push(`Failed to check file permissions: ${error instanceof Error ? error.message : error}`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
isValid: errors.length === 0,
|
|
283
|
+
errors,
|
|
284
|
+
warnings,
|
|
285
|
+
};
|
|
286
|
+
}
|