@shepai/cli 1.175.0 → 1.175.1-pr527.ea242b8
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/apis/json-schema/ActionDispositionEntry.yaml +14 -0
- package/apis/json-schema/DependencyFinding.yaml +28 -0
- package/apis/json-schema/DependencyRiskType.yaml +11 -0
- package/apis/json-schema/DependencyRules.yaml +38 -0
- package/apis/json-schema/EffectivePolicySnapshot.yaml +24 -0
- package/apis/json-schema/FeatureFlags.yaml +5 -0
- package/apis/json-schema/ReleaseIntegrityCheck.yaml +22 -0
- package/apis/json-schema/ReleaseIntegrityCheckType.yaml +9 -0
- package/apis/json-schema/ReleaseIntegrityResult.yaml +16 -0
- package/apis/json-schema/ReleaseRules.yaml +21 -0
- package/apis/json-schema/SecurityActionCategory.yaml +10 -0
- package/apis/json-schema/SecurityActionDisposition.yaml +8 -0
- package/apis/json-schema/SecurityConfig.yaml +17 -0
- package/apis/json-schema/SecurityEvent.yaml +36 -0
- package/apis/json-schema/SecurityMode.yaml +8 -0
- package/apis/json-schema/SecurityPolicy.yaml +24 -0
- package/apis/json-schema/SecuritySeverity.yaml +9 -0
- package/apis/json-schema/Settings.yaml +3 -0
- package/dist/packages/core/src/application/ports/output/agents/agent-executor.interface.d.ts +15 -1
- package/dist/packages/core/src/application/ports/output/agents/agent-executor.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts +3 -1
- package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/repositories/security-event.repository.interface.d.ts +76 -0
- package/dist/packages/core/src/application/ports/output/repositories/security-event.repository.interface.d.ts.map +1 -0
- package/dist/packages/core/src/application/ports/output/repositories/security-event.repository.interface.js +11 -0
- package/dist/packages/core/src/application/ports/output/services/github-repository-service.interface.d.ts +38 -0
- package/dist/packages/core/src/application/ports/output/services/github-repository-service.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/github-repository-service.interface.js +9 -0
- package/dist/packages/core/src/application/ports/output/services/security-policy-service.interface.d.ts +77 -0
- package/dist/packages/core/src/application/ports/output/services/security-policy-service.interface.d.ts.map +1 -0
- package/dist/packages/core/src/application/ports/output/services/security-policy-service.interface.js +13 -0
- package/dist/packages/core/src/application/ports/output/services/spec-initializer.interface.d.ts +11 -0
- package/dist/packages/core/src/application/ports/output/services/spec-initializer.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.js +2 -0
- package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.js +2 -0
- package/dist/packages/core/src/application/use-cases/features/check-and-unblock-features.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/check-and-unblock-features.use-case.js +2 -0
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/create-feature.use-case.js +1 -0
- package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/resume-feature.use-case.js +2 -0
- package/dist/packages/core/src/application/use-cases/features/start-feature.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/start-feature.use-case.js +2 -0
- package/dist/packages/core/src/application/use-cases/security/enforce-security.use-case.d.ts +71 -0
- package/dist/packages/core/src/application/use-cases/security/enforce-security.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/security/enforce-security.use-case.js +215 -0
- package/dist/packages/core/src/application/use-cases/security/evaluate-security-policy.use-case.d.ts +24 -0
- package/dist/packages/core/src/application/use-cases/security/evaluate-security-policy.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/security/evaluate-security-policy.use-case.js +56 -0
- package/dist/packages/core/src/application/use-cases/security/get-security-state.use-case.d.ts +36 -0
- package/dist/packages/core/src/application/use-cases/security/get-security-state.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/security/get-security-state.use-case.js +76 -0
- package/dist/packages/core/src/application/use-cases/security/record-security-event.use-case.d.ts +14 -0
- package/dist/packages/core/src/application/use-cases/security/record-security-event.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/security/record-security-event.use-case.js +46 -0
- package/dist/packages/core/src/domain/errors/security-violation.error.d.ts +15 -0
- package/dist/packages/core/src/domain/errors/security-violation.error.d.ts.map +1 -0
- package/dist/packages/core/src/domain/errors/security-violation.error.js +20 -0
- package/dist/packages/core/src/domain/factories/settings-defaults.factory.d.ts.map +1 -1
- package/dist/packages/core/src/domain/factories/settings-defaults.factory.js +6 -1
- package/dist/packages/core/src/domain/generated/output.d.ts +263 -0
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/packages/core/src/domain/generated/output.js +43 -0
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +57 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/security-event.mapper.d.ts +44 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/security-event.mapper.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/security-event.mapper.js +55 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/settings.mapper.d.ts +4 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/settings.mapper.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/persistence/sqlite/mappers/settings.mapper.js +17 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/053-add-security-settings-columns.d.ts +18 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/053-add-security-settings-columns.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/053-add-security-settings-columns.js +31 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/054-create-security-events-table.d.ts +29 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/054-create-security-events-table.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/054-create-security-events-table.js +53 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/056-add-feature-flag-supply-chain-security.d.ts +16 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/056-add-feature-flag-supply-chain-security.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations/056-add-feature-flag-supply-chain-security.js +22 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-security-event.repository.d.ts +24 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-security-event.repository.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-security-event.repository.js +96 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-settings.repository.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/repositories/sqlite-settings.repository.js +15 -3
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js +12 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-interactive-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/claude-code-interactive-executor.service.js +44 -4
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/security-constraint-validator.d.ts +22 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/security-constraint-validator.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/security-constraint-validator.js +30 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/fast-feature-agent-graph.d.ts +10 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/fast-feature-agent-graph.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +35 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +3 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +7 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +3 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +32 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +25 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/security-pre-check.d.ts +59 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/security-pre-check.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/security-pre-check.js +89 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts +4 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.js +10 -0
- package/dist/packages/core/src/infrastructure/services/external/github-repository.service.d.ts +10 -1
- package/dist/packages/core/src/infrastructure/services/external/github-repository.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/external/github-repository.service.js +101 -1
- package/dist/packages/core/src/infrastructure/services/security/dependency-risk-evaluator.d.ts +53 -0
- package/dist/packages/core/src/infrastructure/services/security/dependency-risk-evaluator.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/security/dependency-risk-evaluator.js +241 -0
- package/dist/packages/core/src/infrastructure/services/security/release-integrity-evaluator.d.ts +44 -0
- package/dist/packages/core/src/infrastructure/services/security/release-integrity-evaluator.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/security/release-integrity-evaluator.js +194 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy-file-reader.d.ts +28 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy-file-reader.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy-file-reader.js +50 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy-validator.d.ts +26 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy-validator.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy-validator.js +147 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy.service.d.ts +44 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/security/security-policy.service.js +174 -0
- package/dist/packages/core/src/infrastructure/services/spec/spec-initializer.service.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/services/spec/spec-initializer.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/spec/spec-initializer.service.js +61 -0
- package/dist/src/presentation/cli/commands/security.command.d.ts +16 -0
- package/dist/src/presentation/cli/commands/security.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/security.command.js +133 -0
- package/dist/src/presentation/cli/index.js +2 -0
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +5 -1
- package/dist/src/presentation/web/app/actions/security.d.ts +28 -0
- package/dist/src/presentation/web/app/actions/security.d.ts.map +1 -0
- package/dist/src/presentation/web/app/actions/security.js +59 -0
- package/dist/src/presentation/web/app/build-graph-nodes.d.ts +3 -1
- package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
- package/dist/src/presentation/web/app/build-graph-nodes.js +2 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts +3 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.js +2 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-drawer.d.ts +3 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-drawer.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-drawer.js +3 -2
- package/dist/src/presentation/web/components/common/repository-node/security-panel.d.ts +6 -0
- package/dist/src/presentation/web/components/common/repository-node/security-panel.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/repository-node/security-panel.js +29 -0
- package/dist/src/presentation/web/components/common/repository-node/security-panel.stories.d.ts +10 -0
- package/dist/src/presentation/web/components/common/repository-node/security-panel.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/repository-node/security-panel.stories.js +53 -0
- package/dist/src/presentation/web/components/common/security-badge.d.ts +7 -0
- package/dist/src/presentation/web/components/common/security-badge.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/security-badge.js +30 -0
- package/dist/src/presentation/web/components/common/security-badge.stories.d.ts +12 -0
- package/dist/src/presentation/web/components/common/security-badge.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/common/security-badge.stories.js +20 -0
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.js +3 -0
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/feature-flags-settings-section.stories.js +3 -0
- package/dist/src/presentation/web/components/features/settings/settings-page-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/settings-page-client.js +26 -7
- package/dist/src/presentation/web/components/features/settings/settings-page-client.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/settings/settings-page-client.stories.js +1 -0
- package/dist/src/presentation/web/components/features/settings/supply-chain-security-settings-section.d.ts +6 -0
- package/dist/src/presentation/web/components/features/settings/supply-chain-security-settings-section.d.ts.map +1 -0
- package/dist/src/presentation/web/components/features/settings/supply-chain-security-settings-section.js +60 -0
- package/dist/src/presentation/web/components/features/settings/supply-chain-security-settings-section.stories.d.ts +14 -0
- package/dist/src/presentation/web/components/features/settings/supply-chain-security-settings-section.stories.d.ts.map +1 -0
- package/dist/src/presentation/web/components/features/settings/supply-chain-security-settings-section.stories.js +116 -0
- package/dist/translations/ar/cli.json +21 -0
- package/dist/translations/ar/web.json +43 -1
- package/dist/translations/de/cli.json +21 -0
- package/dist/translations/de/web.json +43 -1
- package/dist/translations/en/cli.json +21 -0
- package/dist/translations/en/web.json +43 -1
- package/dist/translations/es/cli.json +21 -0
- package/dist/translations/es/web.json +43 -1
- package/dist/translations/fr/cli.json +21 -0
- package/dist/translations/fr/web.json +43 -1
- package/dist/translations/he/cli.json +21 -0
- package/dist/translations/he/web.json +43 -1
- package/dist/translations/pt/cli.json +22 -1
- package/dist/translations/pt/web.json +43 -1
- package/dist/translations/ru/cli.json +21 -0
- package/dist/translations/ru/web.json +43 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +29 -29
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/@drawer/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +38 -38
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +38 -38
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/chat/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/chat/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/chat/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +38 -38
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +38 -38
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +27 -27
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
- package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
- package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
- package/web/.next/server/app/api/interactive/chat/[featureId]/messages/route.js.nft.json +1 -1
- package/web/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/web/.next/server/app/api/sessions-batch/route.js.nft.json +1 -1
- package/web/.next/server/app/features/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/features/page.js.nft.json +1 -1
- package/web/.next/server/app/features/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +33 -18
- package/web/.next/server/app/settings/page.js +1 -1
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +13 -13
- package/web/.next/server/app/skills/page.js.nft.json +1 -1
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +11 -11
- package/web/.next/server/app/tools/page.js.nft.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__c78383b1._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__c78383b1._.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__cd67a84c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_ad0071c9.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_ad0071c9.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_chat_page_actions_90d98b2b.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_chat_page_actions_90d98b2b.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_chat_page_actions_d3828105.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_chat_page_actions_d3828105.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js +2 -2
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_feature-drawer-client_tsx_e9755fc8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1f389e5d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__51ec77a8._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__51ec77a8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__540c615f._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__540c615f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__66047a1b._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__66047a1b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6c7d3936._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6c7d3936._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a2d6c0ac._.js +4 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a2d6c0ac._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a932cd3a._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a932cd3a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aa72e794._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aa72e794._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__b7b96453._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_08eaf4b1._.js +3 -0
- package/web/.next/server/chunks/ssr/_08eaf4b1._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_295fffde._.js +1 -1
- package/web/.next/server/chunks/ssr/_295fffde._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_45496654._.js +1 -1
- package/web/.next/server/chunks/ssr/_45496654._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_4cbb7f95._.js +1 -1
- package/web/.next/server/chunks/ssr/_4cbb7f95._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js +1 -1
- package/web/.next/server/chunks/ssr/_56b9d60f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_6abfa39e._.js +1 -1
- package/web/.next/server/chunks/ssr/_783debcb._.js +9 -0
- package/web/.next/server/chunks/ssr/_783debcb._.js.map +1 -0
- package/web/.next/server/chunks/ssr/{_af6b8b94._.js → _e7f76333._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_af6b8b94._.js.map → _e7f76333._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_f8c55130._.js +1 -1
- package/web/.next/server/chunks/ssr/_f8c55130._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_e0dd6fcf._.js → _fc1578d7._.js} +2 -2
- package/web/.next/server/chunks/ssr/_fc1578d7._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_ff04802c._.js +3 -0
- package/web/.next/server/chunks/ssr/_ff04802c._.js.map +1 -0
- package/web/.next/server/chunks/ssr/_ff87ffa6._.js +3 -0
- package/web/.next/server/chunks/ssr/_ff87ffa6._.js.map +1 -0
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js +1 -1
- package/web/.next/server/chunks/ssr/f3a1f_components_common_control-center-drawer_repository-drawer-client_tsx_39a00c03._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_17d39233._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_17d39233._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_54b02639._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_54b02639._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_7b7b9e3b._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_7b7b9e3b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_807cba76._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_807cba76._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_90b5e66e.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_90b5e66e.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_4ce30db7.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_4ce30db7.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_e4032193.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_e4032193.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_app_actions_open-ide_ts_baaca5d5._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_895e5bfa._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_skills_8a174cac._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_skills_8a174cac._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_db9fa0c2._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_db9fa0c2._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e1cd1869._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e1cd1869._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e3a30e30._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_e3a30e30._.js.map +1 -1
- package/web/.next/server/chunks/ssr/translations_23dd5e7e._.js +1 -1
- package/web/.next/server/chunks/ssr/translations_23dd5e7e._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +74 -59
- package/web/.next/static/chunks/{238fdbed09dc61b6.js → 1eeabda286169861.js} +2 -2
- package/web/.next/static/chunks/20ec94c610d07a10.css +1 -0
- package/web/.next/static/chunks/{940c842293a6ee9b.js → 2dcae7bd1f3e2b51.js} +1 -1
- package/web/.next/static/chunks/3aba9d2242420cb5.js +1 -0
- package/web/.next/static/chunks/6003ad985fb78e62.js +1 -0
- package/web/.next/static/chunks/{0b07ee72b0c639ef.js → 69aa6a996dccb7dc.js} +2 -2
- package/web/.next/static/chunks/{873e837cd1179cdd.js → 6e5aeb5da5bb2ab6.js} +1 -1
- package/web/.next/static/chunks/{2ad924f5ba5ec0a6.js → 7c8e1ab108e3ceea.js} +1 -1
- package/web/.next/static/chunks/{bc41a393614b1192.js → 825ddcb7c361b2fe.js} +1 -1
- package/web/.next/static/chunks/{a22ee308ae1509ca.js → 89a6182ae40ac10b.js} +1 -1
- package/web/.next/static/chunks/{d26542df5ecc8717.js → a6d516b7e128f889.js} +1 -1
- package/web/.next/static/chunks/ae81796726a9bba3.js +1 -0
- package/web/.next/static/chunks/{b49ab0b290e9342d.js → b46545caae3b4930.js} +1 -1
- package/web/.next/static/chunks/{b7b5d65a5dd2fff1.js → c43f00ac45c5381d.js} +1 -1
- package/web/.next/static/chunks/{39054eabee156e55.js → c741f40bcb2abe54.js} +3 -3
- package/web/.next/static/chunks/{1b336d1266a0aa3d.js → dfc05704351fc940.js} +1 -1
- package/web/.next/static/chunks/eb72ac7aa8986962.js +1 -0
- package/web/.next/static/chunks/eef5d47669e61a54.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1cd4327c._.js +0 -4
- package/web/.next/server/chunks/ssr/[root-of-the-server]__1cd4327c._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_2b021b35._.js +0 -3
- package/web/.next/server/chunks/ssr/_2b021b35._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_43ba79e7._.js +0 -3
- package/web/.next/server/chunks/ssr/_43ba79e7._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_7cb0396e._.js +0 -3
- package/web/.next/server/chunks/ssr/_7cb0396e._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_e0dd6fcf._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_e680c57c._.js +0 -9
- package/web/.next/server/chunks/ssr/_e680c57c._.js.map +0 -1
- package/web/.next/static/chunks/28f6b1cab38ab025.js +0 -3
- package/web/.next/static/chunks/8b0a9cb5109fe899.js +0 -1
- package/web/.next/static/chunks/a20f2d6f76f469b7.css +0 -1
- package/web/.next/static/chunks/b2aa69e4b0b032d9.js +0 -1
- package/web/.next/static/chunks/b65e555419a0c664.js +0 -1
- package/web/.next/static/chunks/ba0e0fa2d1a650bb.js +0 -1
- /package/web/.next/static/{9rcv3ICw0kZNuv3TVdO8E → 4jtpgWCvk_Q6-K-puXRhW}/_buildManifest.js +0 -0
- /package/web/.next/static/{9rcv3ICw0kZNuv3TVdO8E → 4jtpgWCvk_Q6-K-puXRhW}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{9rcv3ICw0kZNuv3TVdO8E → 4jtpgWCvk_Q6-K-puXRhW}/_ssgManifest.js +0 -0
package/dist/packages/core/src/infrastructure/services/security/release-integrity-evaluator.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Release Integrity Evaluator
|
|
3
|
+
*
|
|
4
|
+
* Checks release pipeline integrity for a repository:
|
|
5
|
+
* - CI workflow exists and publishes from CI (not local)
|
|
6
|
+
* - NPM_TOKEN and RELEASE_TOKEN referenced as secrets (not hardcoded)
|
|
7
|
+
* - npm provenance flags (--provenance) present in publish steps
|
|
8
|
+
* - Release workflow integrity (semantic-release configured)
|
|
9
|
+
*
|
|
10
|
+
* Returns a ReleaseIntegrityResult with individual check results and overall pass/fail.
|
|
11
|
+
*/
|
|
12
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
13
|
+
import { join } from 'node:path';
|
|
14
|
+
import { ReleaseIntegrityCheckType, SecuritySeverity } from '../../../domain/generated/output.js';
|
|
15
|
+
/**
|
|
16
|
+
* Token env var names that should use secrets.* references.
|
|
17
|
+
*/
|
|
18
|
+
const TOKEN_ENV_NAMES = ['GITHUB_TOKEN', 'RELEASE_TOKEN', 'NPM_TOKEN', 'NODE_AUTH_TOKEN'];
|
|
19
|
+
/**
|
|
20
|
+
* Pattern for a secrets.* reference in a YAML value.
|
|
21
|
+
*/
|
|
22
|
+
const SECRETS_REF_PATTERN = /\$\{\{\s*secrets\./;
|
|
23
|
+
/**
|
|
24
|
+
* Pattern for detecting npm publish commands.
|
|
25
|
+
*/
|
|
26
|
+
const NPM_PUBLISH_PATTERN = /npm\s+publish/;
|
|
27
|
+
/**
|
|
28
|
+
* Pattern for detecting --provenance flag.
|
|
29
|
+
*/
|
|
30
|
+
const PROVENANCE_FLAG_PATTERN = /--provenance/;
|
|
31
|
+
/**
|
|
32
|
+
* Pattern for detecting semantic-release.
|
|
33
|
+
*/
|
|
34
|
+
const SEMANTIC_RELEASE_PATTERN = /semantic-release/;
|
|
35
|
+
export class ReleaseIntegrityEvaluator {
|
|
36
|
+
/**
|
|
37
|
+
* Evaluate release pipeline integrity.
|
|
38
|
+
*
|
|
39
|
+
* @param repositoryPath - Absolute path to the repository root
|
|
40
|
+
* @param rules - Release integrity policy rules
|
|
41
|
+
* @returns Aggregated result with individual check details
|
|
42
|
+
*/
|
|
43
|
+
evaluate(repositoryPath, rules) {
|
|
44
|
+
const checks = [];
|
|
45
|
+
const workflowDir = join(repositoryPath, '.github', 'workflows');
|
|
46
|
+
// Read all workflow files
|
|
47
|
+
const workflowContents = this.readWorkflowFiles(workflowDir);
|
|
48
|
+
// Check CI-only publishing
|
|
49
|
+
if (rules.requireCiOnlyPublishing) {
|
|
50
|
+
checks.push(this.checkCiOnlyPublishing(workflowDir, workflowContents));
|
|
51
|
+
}
|
|
52
|
+
// Check secret configuration (no hardcoded tokens)
|
|
53
|
+
if (rules.requireCiOnlyPublishing) {
|
|
54
|
+
checks.push(this.checkSecretConfiguration(workflowContents));
|
|
55
|
+
}
|
|
56
|
+
// Check provenance configuration
|
|
57
|
+
if (rules.requireProvenance) {
|
|
58
|
+
checks.push(...this.checkProvenanceConfiguration(workflowContents));
|
|
59
|
+
}
|
|
60
|
+
// Check workflow integrity
|
|
61
|
+
if (rules.checkWorkflowIntegrity) {
|
|
62
|
+
checks.push(this.checkWorkflowIntegrity(workflowContents));
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
checks,
|
|
66
|
+
passed: checks.length === 0 || checks.every((c) => c.passed),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Read all YAML workflow files from .github/workflows/.
|
|
71
|
+
*/
|
|
72
|
+
readWorkflowFiles(workflowDir) {
|
|
73
|
+
if (!existsSync(workflowDir)) {
|
|
74
|
+
return [];
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const files = readdirSync(workflowDir).filter((f) => f.endsWith('.yml') || f.endsWith('.yaml'));
|
|
78
|
+
return files.map((f) => readFileSync(join(workflowDir, f), 'utf-8'));
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Check that CI workflow files exist (publishing happens in CI, not locally).
|
|
86
|
+
*/
|
|
87
|
+
checkCiOnlyPublishing(workflowDir, workflowContents) {
|
|
88
|
+
if (workflowContents.length === 0) {
|
|
89
|
+
return {
|
|
90
|
+
checkType: ReleaseIntegrityCheckType.CiOnlyPublishing,
|
|
91
|
+
passed: false,
|
|
92
|
+
message: 'No CI workflow files found in .github/workflows/. Publishing must happen in CI, not locally.',
|
|
93
|
+
severity: SecuritySeverity.Critical,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
checkType: ReleaseIntegrityCheckType.CiOnlyPublishing,
|
|
98
|
+
passed: true,
|
|
99
|
+
message: 'CI workflow files found. Publishing is configured for CI execution.',
|
|
100
|
+
severity: SecuritySeverity.Critical,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Check that tokens are referenced as secrets, not hardcoded.
|
|
105
|
+
* Scans for known token env var names and verifies they use ${{ secrets.* }}.
|
|
106
|
+
*/
|
|
107
|
+
checkSecretConfiguration(workflowContents) {
|
|
108
|
+
const allContent = workflowContents.join('\n');
|
|
109
|
+
const lines = allContent.split('\n');
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
const trimmed = line.trim();
|
|
112
|
+
for (const tokenName of TOKEN_ENV_NAMES) {
|
|
113
|
+
// Match lines like "NPM_TOKEN: value" or "NPM_TOKEN: 'value'"
|
|
114
|
+
const pattern = new RegExp(`^${tokenName}\\s*:\\s*(.+)$`);
|
|
115
|
+
const match = pattern.exec(trimmed);
|
|
116
|
+
if (match) {
|
|
117
|
+
const value = match[1].trim();
|
|
118
|
+
// Value must contain a secrets.* reference to be safe
|
|
119
|
+
if (!SECRETS_REF_PATTERN.test(value)) {
|
|
120
|
+
return {
|
|
121
|
+
checkType: ReleaseIntegrityCheckType.SecretConfiguration,
|
|
122
|
+
passed: false,
|
|
123
|
+
message: 'Hardcoded token detected in workflow files. Tokens must use ${{ secrets.* }} references.',
|
|
124
|
+
severity: SecuritySeverity.Critical,
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
checkType: ReleaseIntegrityCheckType.SecretConfiguration,
|
|
132
|
+
passed: true,
|
|
133
|
+
message: 'Tokens are properly referenced using ${{ secrets.* }} expressions.',
|
|
134
|
+
severity: SecuritySeverity.Critical,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check that npm publish commands include --provenance flag.
|
|
139
|
+
*/
|
|
140
|
+
checkProvenanceConfiguration(workflowContents) {
|
|
141
|
+
const allContent = workflowContents.join('\n');
|
|
142
|
+
// If no npm publish commands found, provenance is not applicable
|
|
143
|
+
if (!NPM_PUBLISH_PATTERN.test(allContent)) {
|
|
144
|
+
return [];
|
|
145
|
+
}
|
|
146
|
+
// Check if all npm publish commands have --provenance
|
|
147
|
+
const lines = allContent.split('\n');
|
|
148
|
+
let hasPublishWithoutProvenance = false;
|
|
149
|
+
for (const line of lines) {
|
|
150
|
+
if (NPM_PUBLISH_PATTERN.test(line) && !PROVENANCE_FLAG_PATTERN.test(line)) {
|
|
151
|
+
hasPublishWithoutProvenance = true;
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
if (hasPublishWithoutProvenance) {
|
|
156
|
+
return [
|
|
157
|
+
{
|
|
158
|
+
checkType: ReleaseIntegrityCheckType.ProvenanceConfiguration,
|
|
159
|
+
passed: false,
|
|
160
|
+
message: 'npm publish command found without --provenance flag. Add --provenance to generate SLSA provenance attestations.',
|
|
161
|
+
severity: SecuritySeverity.Medium,
|
|
162
|
+
},
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
return [
|
|
166
|
+
{
|
|
167
|
+
checkType: ReleaseIntegrityCheckType.ProvenanceConfiguration,
|
|
168
|
+
passed: true,
|
|
169
|
+
message: 'npm publish commands include --provenance flag for SLSA provenance.',
|
|
170
|
+
severity: SecuritySeverity.Medium,
|
|
171
|
+
},
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Check workflow integrity (semantic-release is configured).
|
|
176
|
+
*/
|
|
177
|
+
checkWorkflowIntegrity(workflowContents) {
|
|
178
|
+
const allContent = workflowContents.join('\n');
|
|
179
|
+
if (!SEMANTIC_RELEASE_PATTERN.test(allContent)) {
|
|
180
|
+
return {
|
|
181
|
+
checkType: ReleaseIntegrityCheckType.WorkflowIntegrity,
|
|
182
|
+
passed: false,
|
|
183
|
+
message: 'semantic-release not found in CI workflows. Automated release management is recommended.',
|
|
184
|
+
severity: SecuritySeverity.Medium,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
checkType: ReleaseIntegrityCheckType.WorkflowIntegrity,
|
|
189
|
+
passed: true,
|
|
190
|
+
message: 'semantic-release is configured in CI workflows.',
|
|
191
|
+
severity: SecuritySeverity.Medium,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
}
|
package/dist/packages/core/src/infrastructure/services/security/security-policy-file-reader.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Policy File Reader
|
|
3
|
+
*
|
|
4
|
+
* Reads and parses shep.security.yaml from a repository root using js-yaml.
|
|
5
|
+
* Returns the parsed object or null if the file does not exist.
|
|
6
|
+
* Throws with actionable messages on YAML syntax errors.
|
|
7
|
+
*
|
|
8
|
+
* Uses DEFAULT_SCHEMA to prevent arbitrary code execution from YAML tags.
|
|
9
|
+
*/
|
|
10
|
+
import type { SecurityPolicy } from '../../../domain/generated/output.js';
|
|
11
|
+
/**
|
|
12
|
+
* The filename for the security policy file at the repository root.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SECURITY_POLICY_FILENAME = "shep.security.yaml";
|
|
15
|
+
/**
|
|
16
|
+
* Reads and parses the security policy YAML file from a repository.
|
|
17
|
+
*/
|
|
18
|
+
export declare class SecurityPolicyFileReader {
|
|
19
|
+
/**
|
|
20
|
+
* Read and parse the security policy file from the given repository path.
|
|
21
|
+
*
|
|
22
|
+
* @param repositoryPath - Absolute path to the repository root
|
|
23
|
+
* @returns Parsed policy object, or null if file does not exist or is empty
|
|
24
|
+
* @throws Error with actionable message if YAML is malformed
|
|
25
|
+
*/
|
|
26
|
+
read(repositoryPath: string): Promise<Partial<SecurityPolicy> | null>;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=security-policy-file-reader.d.ts.map
|
package/dist/packages/core/src/infrastructure/services/security/security-policy-file-reader.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-policy-file-reader.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/security/security-policy-file-reader.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAE1E;;GAEG;AACH,eAAO,MAAM,wBAAwB,uBAAuB,CAAC;AAE7D;;GAEG;AACH,qBAAa,wBAAwB;IACnC;;;;;;OAMG;IACG,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAAC;CA0B5E"}
|
package/dist/packages/core/src/infrastructure/services/security/security-policy-file-reader.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Policy File Reader
|
|
3
|
+
*
|
|
4
|
+
* Reads and parses shep.security.yaml from a repository root using js-yaml.
|
|
5
|
+
* Returns the parsed object or null if the file does not exist.
|
|
6
|
+
* Throws with actionable messages on YAML syntax errors.
|
|
7
|
+
*
|
|
8
|
+
* Uses DEFAULT_SCHEMA to prevent arbitrary code execution from YAML tags.
|
|
9
|
+
*/
|
|
10
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
11
|
+
import { join } from 'node:path';
|
|
12
|
+
import yaml from 'js-yaml';
|
|
13
|
+
/**
|
|
14
|
+
* The filename for the security policy file at the repository root.
|
|
15
|
+
*/
|
|
16
|
+
export const SECURITY_POLICY_FILENAME = 'shep.security.yaml';
|
|
17
|
+
/**
|
|
18
|
+
* Reads and parses the security policy YAML file from a repository.
|
|
19
|
+
*/
|
|
20
|
+
export class SecurityPolicyFileReader {
|
|
21
|
+
/**
|
|
22
|
+
* Read and parse the security policy file from the given repository path.
|
|
23
|
+
*
|
|
24
|
+
* @param repositoryPath - Absolute path to the repository root
|
|
25
|
+
* @returns Parsed policy object, or null if file does not exist or is empty
|
|
26
|
+
* @throws Error with actionable message if YAML is malformed
|
|
27
|
+
*/
|
|
28
|
+
async read(repositoryPath) {
|
|
29
|
+
const filePath = join(repositoryPath, SECURITY_POLICY_FILENAME);
|
|
30
|
+
if (!existsSync(filePath)) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
34
|
+
try {
|
|
35
|
+
const parsed = yaml.load(content, {
|
|
36
|
+
schema: yaml.DEFAULT_SCHEMA,
|
|
37
|
+
filename: SECURITY_POLICY_FILENAME,
|
|
38
|
+
});
|
|
39
|
+
// Empty file or comment-only file yields null/undefined
|
|
40
|
+
if (parsed == null || typeof parsed !== 'object') {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return parsed;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
47
|
+
throw new Error(`Failed to parse ${SECURITY_POLICY_FILENAME}: ${message}`);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
package/dist/packages/core/src/infrastructure/services/security/security-policy-validator.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Policy Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates a parsed security policy object against the expected schema.
|
|
5
|
+
* Checks required fields, valid enum values, contradictory rules,
|
|
6
|
+
* and reasonable input limits. Returns structured validation results
|
|
7
|
+
* with per-field error messages.
|
|
8
|
+
*/
|
|
9
|
+
import type { PolicyValidationResult } from '../../../application/ports/output/services/security-policy-service.interface.js';
|
|
10
|
+
/**
|
|
11
|
+
* Validates parsed security policy objects against the expected schema.
|
|
12
|
+
*/
|
|
13
|
+
export declare class SecurityPolicyValidator {
|
|
14
|
+
/**
|
|
15
|
+
* Validate a parsed policy object.
|
|
16
|
+
*
|
|
17
|
+
* @param policy - The parsed policy object (from YAML)
|
|
18
|
+
* @returns Validation result with errors array
|
|
19
|
+
*/
|
|
20
|
+
validate(policy: Record<string, unknown>): PolicyValidationResult;
|
|
21
|
+
private validateActionDispositions;
|
|
22
|
+
private validateDependencyRules;
|
|
23
|
+
private validateReleaseRules;
|
|
24
|
+
private validateStringList;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=security-policy-validator.d.ts.map
|
package/dist/packages/core/src/infrastructure/services/security/security-policy-validator.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-policy-validator.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/security/security-policy-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iFAAiF,CAAC;AAY9H;;GAEG;AACH,qBAAa,uBAAuB;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,sBAAsB;IAiCjE,OAAO,CAAC,0BAA0B;IAwDlC,OAAO,CAAC,uBAAuB;IAgC/B,OAAO,CAAC,oBAAoB;IAqB5B,OAAO,CAAC,kBAAkB;CAgB3B"}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Policy Validator
|
|
3
|
+
*
|
|
4
|
+
* Validates a parsed security policy object against the expected schema.
|
|
5
|
+
* Checks required fields, valid enum values, contradictory rules,
|
|
6
|
+
* and reasonable input limits. Returns structured validation results
|
|
7
|
+
* with per-field error messages.
|
|
8
|
+
*/
|
|
9
|
+
import { SecurityMode, SecurityActionCategory, SecurityActionDisposition, } from '../../../domain/generated/output.js';
|
|
10
|
+
/** Maximum number of action disposition entries allowed */
|
|
11
|
+
const MAX_ACTION_DISPOSITIONS = 100;
|
|
12
|
+
/** Maximum number of entries in allowlist or denylist */
|
|
13
|
+
const MAX_LIST_ENTRIES = 100;
|
|
14
|
+
const VALID_MODES = Object.values(SecurityMode);
|
|
15
|
+
const VALID_CATEGORIES = Object.values(SecurityActionCategory);
|
|
16
|
+
const VALID_DISPOSITIONS = Object.values(SecurityActionDisposition);
|
|
17
|
+
/**
|
|
18
|
+
* Validates parsed security policy objects against the expected schema.
|
|
19
|
+
*/
|
|
20
|
+
export class SecurityPolicyValidator {
|
|
21
|
+
/**
|
|
22
|
+
* Validate a parsed policy object.
|
|
23
|
+
*
|
|
24
|
+
* @param policy - The parsed policy object (from YAML)
|
|
25
|
+
* @returns Validation result with errors array
|
|
26
|
+
*/
|
|
27
|
+
validate(policy) {
|
|
28
|
+
const errors = [];
|
|
29
|
+
// Validate mode (optional, but if present must be valid)
|
|
30
|
+
if (policy.mode !== undefined) {
|
|
31
|
+
if (!VALID_MODES.includes(policy.mode)) {
|
|
32
|
+
errors.push(`Invalid mode: "${String(policy.mode)}". Valid values: ${VALID_MODES.join(', ')}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// Validate actionDispositions (optional, but if present must be valid)
|
|
36
|
+
if (policy.actionDispositions !== undefined) {
|
|
37
|
+
this.validateActionDispositions(policy.actionDispositions, errors);
|
|
38
|
+
}
|
|
39
|
+
// Validate dependencyRules (optional, but if present must be valid)
|
|
40
|
+
if (policy.dependencyRules !== undefined) {
|
|
41
|
+
this.validateDependencyRules(policy.dependencyRules, errors);
|
|
42
|
+
}
|
|
43
|
+
// Validate releaseRules (optional, but if present must be valid)
|
|
44
|
+
if (policy.releaseRules !== undefined) {
|
|
45
|
+
this.validateReleaseRules(policy.releaseRules, errors);
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
valid: errors.length === 0,
|
|
49
|
+
errors,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
validateActionDispositions(value, errors) {
|
|
53
|
+
if (!Array.isArray(value)) {
|
|
54
|
+
errors.push('actionDispositions must be an array');
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (value.length > MAX_ACTION_DISPOSITIONS) {
|
|
58
|
+
errors.push(`actionDispositions exceeds limit: ${value.length} entries (max ${MAX_ACTION_DISPOSITIONS})`);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
// Track categories to detect contradictions
|
|
62
|
+
const categoryToDisposition = new Map();
|
|
63
|
+
for (let i = 0; i < value.length; i++) {
|
|
64
|
+
const entry = value[i];
|
|
65
|
+
if (!entry || typeof entry !== 'object') {
|
|
66
|
+
errors.push(`actionDispositions[${i}] must be an object`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const category = entry.category;
|
|
70
|
+
const disposition = entry.disposition;
|
|
71
|
+
if (!VALID_CATEGORIES.includes(category)) {
|
|
72
|
+
errors.push(`actionDispositions[${i}].category: invalid value "${String(category)}". Valid values: ${VALID_CATEGORIES.join(', ')}`);
|
|
73
|
+
}
|
|
74
|
+
if (!VALID_DISPOSITIONS.includes(disposition)) {
|
|
75
|
+
errors.push(`actionDispositions[${i}].disposition: invalid value "${String(disposition)}". Valid values: ${VALID_DISPOSITIONS.join(', ')}`);
|
|
76
|
+
}
|
|
77
|
+
// Check for contradictory entries (same category, different disposition)
|
|
78
|
+
if (VALID_CATEGORIES.includes(category) &&
|
|
79
|
+
VALID_DISPOSITIONS.includes(disposition)) {
|
|
80
|
+
const existing = categoryToDisposition.get(category);
|
|
81
|
+
if (existing !== undefined && existing !== disposition) {
|
|
82
|
+
errors.push(`Contradictory action dispositions for category "${category}": "${existing}" vs "${disposition}"`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
categoryToDisposition.set(category, disposition);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
validateDependencyRules(value, errors) {
|
|
91
|
+
if (!value || typeof value !== 'object') {
|
|
92
|
+
errors.push('dependencyRules must be an object');
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
const rules = value;
|
|
96
|
+
// Validate boolean fields
|
|
97
|
+
const booleanFields = [
|
|
98
|
+
'checkLockfileConsistency',
|
|
99
|
+
'checkLifecycleScripts',
|
|
100
|
+
'checkNonRegistrySource',
|
|
101
|
+
'enforceStrictVersionRanges',
|
|
102
|
+
];
|
|
103
|
+
for (const field of booleanFields) {
|
|
104
|
+
if (rules[field] !== undefined && typeof rules[field] !== 'boolean') {
|
|
105
|
+
errors.push(`dependencyRules.${field} must be a boolean, got ${typeof rules[field]}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Validate list fields
|
|
109
|
+
if (rules.allowlist !== undefined) {
|
|
110
|
+
this.validateStringList('dependencyRules.allowlist', rules.allowlist, errors);
|
|
111
|
+
}
|
|
112
|
+
if (rules.denylist !== undefined) {
|
|
113
|
+
this.validateStringList('dependencyRules.denylist', rules.denylist, errors);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
validateReleaseRules(value, errors) {
|
|
117
|
+
if (!value || typeof value !== 'object') {
|
|
118
|
+
errors.push('releaseRules must be an object');
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
const rules = value;
|
|
122
|
+
const booleanFields = [
|
|
123
|
+
'requireCiOnlyPublishing',
|
|
124
|
+
'requireProvenance',
|
|
125
|
+
'checkWorkflowIntegrity',
|
|
126
|
+
];
|
|
127
|
+
for (const field of booleanFields) {
|
|
128
|
+
if (rules[field] !== undefined && typeof rules[field] !== 'boolean') {
|
|
129
|
+
errors.push(`releaseRules.${field} must be a boolean, got ${typeof rules[field]}`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
validateStringList(path, value, errors) {
|
|
134
|
+
if (!Array.isArray(value)) {
|
|
135
|
+
errors.push(`${path} must be an array`);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (value.length > MAX_LIST_ENTRIES) {
|
|
139
|
+
errors.push(`${path} exceeds limit: ${value.length} entries (max ${MAX_LIST_ENTRIES})`);
|
|
140
|
+
}
|
|
141
|
+
for (let i = 0; i < value.length; i++) {
|
|
142
|
+
if (typeof value[i] !== 'string') {
|
|
143
|
+
errors.push(`${path}[${i}] must be a string`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Policy Service
|
|
3
|
+
*
|
|
4
|
+
* Central policy engine implementing ISecurityPolicyService.
|
|
5
|
+
* Reads the policy file, validates it, merges with persisted settings defaults
|
|
6
|
+
* using deterministic precedence, and returns an EffectivePolicySnapshot.
|
|
7
|
+
*
|
|
8
|
+
* Precedence: global settings defaults < repository policy file (stricter wins).
|
|
9
|
+
* A lower-precedence layer cannot weaken a stricter higher-precedence rule.
|
|
10
|
+
*/
|
|
11
|
+
import { SecurityActionCategory, SecurityActionDisposition } from '../../../domain/generated/output.js';
|
|
12
|
+
import type { EffectivePolicySnapshot } from '../../../domain/generated/output.js';
|
|
13
|
+
import type { ISecurityPolicyService, PolicyValidationResult } from '../../../application/ports/output/services/security-policy-service.interface.js';
|
|
14
|
+
import type { ISettingsRepository } from '../../../application/ports/output/repositories/settings.repository.interface.js';
|
|
15
|
+
import { SecurityPolicyFileReader } from './security-policy-file-reader.js';
|
|
16
|
+
import { SecurityPolicyValidator } from './security-policy-validator.js';
|
|
17
|
+
export declare class SecurityPolicyService implements ISecurityPolicyService {
|
|
18
|
+
private readonly fileReader;
|
|
19
|
+
private readonly validator;
|
|
20
|
+
private readonly settingsRepo;
|
|
21
|
+
private readonly cache;
|
|
22
|
+
constructor(fileReader: SecurityPolicyFileReader, validator: SecurityPolicyValidator, settingsRepo: ISettingsRepository);
|
|
23
|
+
evaluatePolicy(repositoryPath: string): Promise<EffectivePolicySnapshot>;
|
|
24
|
+
getEffectivePolicy(repositoryPath: string): Promise<EffectivePolicySnapshot>;
|
|
25
|
+
validatePolicyFile(filePath: string): Promise<PolicyValidationResult>;
|
|
26
|
+
getActionDisposition(policy: EffectivePolicySnapshot, actionCategory: SecurityActionCategory): SecurityActionDisposition;
|
|
27
|
+
/**
|
|
28
|
+
* Build a default snapshot from settings mode only (no policy file).
|
|
29
|
+
*/
|
|
30
|
+
private buildDefaultSnapshot;
|
|
31
|
+
/**
|
|
32
|
+
* Merge settings defaults with policy file, applying strict-wins precedence.
|
|
33
|
+
*/
|
|
34
|
+
private mergePolicy;
|
|
35
|
+
/**
|
|
36
|
+
* Return the stricter of two SecurityMode values.
|
|
37
|
+
*/
|
|
38
|
+
private stricterMode;
|
|
39
|
+
/**
|
|
40
|
+
* Return the stricter of two SecurityActionDisposition values.
|
|
41
|
+
*/
|
|
42
|
+
private stricterDisposition;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=security-policy.service.d.ts.map
|
package/dist/packages/core/src/infrastructure/services/security/security-policy.service.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security-policy.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/security/security-policy.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAEL,sBAAsB,EACtB,yBAAyB,EAC1B,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EACV,uBAAuB,EAGxB,MAAM,qCAAqC,CAAC;AAC7C,OAAO,KAAK,EACV,sBAAsB,EACtB,sBAAsB,EACvB,MAAM,iFAAiF,CAAC;AACzF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iFAAiF,CAAC;AAC3H,OAAO,EACL,wBAAwB,EAEzB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AA4BzE,qBACa,qBAAsB,YAAW,sBAAsB;IAKhE,OAAO,CAAC,QAAQ,CAAC,UAAU;IAE3B,OAAO,CAAC,QAAQ,CAAC,SAAS;IAE1B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAR/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA8C;gBAIjD,UAAU,EAAE,wBAAwB,EAEpC,SAAS,EAAE,uBAAuB,EAElC,YAAY,EAAE,mBAAmB;IAG9C,cAAc,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA6BxE,kBAAkB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,uBAAuB,CAAC;IAQ5E,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAY3E,oBAAoB,CAClB,MAAM,EAAE,uBAAuB,EAC/B,cAAc,EAAE,sBAAsB,GACrC,yBAAyB;IAK5B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAY5B;;OAEG;IACH,OAAO,CAAC,WAAW;IAuCnB;;OAEG;IACH,OAAO,CAAC,YAAY;IAMpB;;OAEG;IACH,OAAO,CAAC,mBAAmB;CAQ5B"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Policy Service
|
|
3
|
+
*
|
|
4
|
+
* Central policy engine implementing ISecurityPolicyService.
|
|
5
|
+
* Reads the policy file, validates it, merges with persisted settings defaults
|
|
6
|
+
* using deterministic precedence, and returns an EffectivePolicySnapshot.
|
|
7
|
+
*
|
|
8
|
+
* Precedence: global settings defaults < repository policy file (stricter wins).
|
|
9
|
+
* A lower-precedence layer cannot weaken a stricter higher-precedence rule.
|
|
10
|
+
*/
|
|
11
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
12
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
13
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
14
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
15
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
16
|
+
};
|
|
17
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
18
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
19
|
+
};
|
|
20
|
+
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
21
|
+
return function (target, key) { decorator(target, key, paramIndex); }
|
|
22
|
+
};
|
|
23
|
+
import { injectable, inject } from 'tsyringe';
|
|
24
|
+
import { SecurityMode, SecurityActionCategory, SecurityActionDisposition, } from '../../../domain/generated/output.js';
|
|
25
|
+
import { SecurityPolicyFileReader, SECURITY_POLICY_FILENAME, } from './security-policy-file-reader.js';
|
|
26
|
+
import { SecurityPolicyValidator } from './security-policy-validator.js';
|
|
27
|
+
import { dirname } from 'node:path';
|
|
28
|
+
/**
|
|
29
|
+
* Numeric rank for comparing SecurityMode strictness.
|
|
30
|
+
* Higher number = stricter mode.
|
|
31
|
+
*/
|
|
32
|
+
const MODE_STRICTNESS = {
|
|
33
|
+
[SecurityMode.Disabled]: 0,
|
|
34
|
+
[SecurityMode.Advisory]: 1,
|
|
35
|
+
[SecurityMode.Enforce]: 2,
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Numeric rank for comparing disposition strictness.
|
|
39
|
+
* Higher number = more restrictive.
|
|
40
|
+
*/
|
|
41
|
+
const DISPOSITION_STRICTNESS = {
|
|
42
|
+
[SecurityActionDisposition.Allowed]: 0,
|
|
43
|
+
[SecurityActionDisposition.ApprovalRequired]: 1,
|
|
44
|
+
[SecurityActionDisposition.Denied]: 2,
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* All action categories for building default dispositions.
|
|
48
|
+
*/
|
|
49
|
+
const ALL_CATEGORIES = Object.values(SecurityActionCategory);
|
|
50
|
+
let SecurityPolicyService = class SecurityPolicyService {
|
|
51
|
+
fileReader;
|
|
52
|
+
validator;
|
|
53
|
+
settingsRepo;
|
|
54
|
+
cache = new Map();
|
|
55
|
+
constructor(fileReader, validator, settingsRepo) {
|
|
56
|
+
this.fileReader = fileReader;
|
|
57
|
+
this.validator = validator;
|
|
58
|
+
this.settingsRepo = settingsRepo;
|
|
59
|
+
}
|
|
60
|
+
async evaluatePolicy(repositoryPath) {
|
|
61
|
+
// Load settings defaults
|
|
62
|
+
const settings = await this.settingsRepo.load();
|
|
63
|
+
const settingsMode = settings?.security?.mode ?? SecurityMode.Advisory;
|
|
64
|
+
// Read policy file
|
|
65
|
+
const policyFile = await this.fileReader.read(repositoryPath);
|
|
66
|
+
if (!policyFile) {
|
|
67
|
+
// No policy file — use settings defaults
|
|
68
|
+
const snapshot = this.buildDefaultSnapshot(settingsMode);
|
|
69
|
+
this.cache.set(repositoryPath, snapshot);
|
|
70
|
+
return snapshot;
|
|
71
|
+
}
|
|
72
|
+
// Validate policy file
|
|
73
|
+
const validation = this.validator.validate(policyFile);
|
|
74
|
+
if (!validation.valid) {
|
|
75
|
+
throw new Error(`Security policy validation failed for ${repositoryPath}:\n${validation.errors.join('\n')}`);
|
|
76
|
+
}
|
|
77
|
+
// Merge with precedence: settings defaults < policy file (stricter wins)
|
|
78
|
+
const snapshot = this.mergePolicy(settingsMode, policyFile);
|
|
79
|
+
this.cache.set(repositoryPath, snapshot);
|
|
80
|
+
return snapshot;
|
|
81
|
+
}
|
|
82
|
+
async getEffectivePolicy(repositoryPath) {
|
|
83
|
+
const cached = this.cache.get(repositoryPath);
|
|
84
|
+
if (cached) {
|
|
85
|
+
return cached;
|
|
86
|
+
}
|
|
87
|
+
return this.evaluatePolicy(repositoryPath);
|
|
88
|
+
}
|
|
89
|
+
async validatePolicyFile(filePath) {
|
|
90
|
+
// Read the file from the directory containing it
|
|
91
|
+
const dirPath = dirname(filePath);
|
|
92
|
+
const policyFile = await this.fileReader.read(dirPath);
|
|
93
|
+
if (!policyFile) {
|
|
94
|
+
return { valid: true, errors: [] };
|
|
95
|
+
}
|
|
96
|
+
return this.validator.validate(policyFile);
|
|
97
|
+
}
|
|
98
|
+
getActionDisposition(policy, actionCategory) {
|
|
99
|
+
const entry = policy.actionDispositions.find((d) => d.category === actionCategory);
|
|
100
|
+
return entry?.disposition ?? SecurityActionDisposition.Allowed;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build a default snapshot from settings mode only (no policy file).
|
|
104
|
+
*/
|
|
105
|
+
buildDefaultSnapshot(mode) {
|
|
106
|
+
return {
|
|
107
|
+
mode,
|
|
108
|
+
source: 'settings-default',
|
|
109
|
+
evaluatedAt: new Date().toISOString(),
|
|
110
|
+
actionDispositions: ALL_CATEGORIES.map((category) => ({
|
|
111
|
+
category,
|
|
112
|
+
disposition: SecurityActionDisposition.Allowed,
|
|
113
|
+
})),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Merge settings defaults with policy file, applying strict-wins precedence.
|
|
118
|
+
*/
|
|
119
|
+
mergePolicy(settingsMode, policyFile) {
|
|
120
|
+
// Mode: stricter wins
|
|
121
|
+
const fileMode = policyFile.mode ?? SecurityMode.Advisory;
|
|
122
|
+
const effectiveMode = this.stricterMode(settingsMode, fileMode);
|
|
123
|
+
// Action dispositions: merge file entries with defaults, stricter wins
|
|
124
|
+
const dispositionMap = new Map();
|
|
125
|
+
// Start with defaults (all Allowed)
|
|
126
|
+
for (const category of ALL_CATEGORIES) {
|
|
127
|
+
dispositionMap.set(category, SecurityActionDisposition.Allowed);
|
|
128
|
+
}
|
|
129
|
+
// Apply policy file entries (can only make stricter, not weaker)
|
|
130
|
+
if (policyFile.actionDispositions) {
|
|
131
|
+
for (const entry of policyFile.actionDispositions) {
|
|
132
|
+
const current = dispositionMap.get(entry.category);
|
|
133
|
+
if (current !== undefined) {
|
|
134
|
+
dispositionMap.set(entry.category, this.stricterDisposition(current, entry.disposition));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
const actionDispositions = [];
|
|
139
|
+
for (const [category, disposition] of dispositionMap) {
|
|
140
|
+
actionDispositions.push({ category, disposition });
|
|
141
|
+
}
|
|
142
|
+
return {
|
|
143
|
+
mode: effectiveMode,
|
|
144
|
+
source: SECURITY_POLICY_FILENAME,
|
|
145
|
+
evaluatedAt: new Date().toISOString(),
|
|
146
|
+
actionDispositions,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Return the stricter of two SecurityMode values.
|
|
151
|
+
*/
|
|
152
|
+
stricterMode(a, b) {
|
|
153
|
+
const rankA = MODE_STRICTNESS[a] ?? 0;
|
|
154
|
+
const rankB = MODE_STRICTNESS[b] ?? 0;
|
|
155
|
+
return rankA >= rankB ? a : b;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Return the stricter of two SecurityActionDisposition values.
|
|
159
|
+
*/
|
|
160
|
+
stricterDisposition(a, b) {
|
|
161
|
+
const rankA = DISPOSITION_STRICTNESS[a] ?? 0;
|
|
162
|
+
const rankB = DISPOSITION_STRICTNESS[b] ?? 0;
|
|
163
|
+
return rankA >= rankB ? a : b;
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
SecurityPolicyService = __decorate([
|
|
167
|
+
injectable(),
|
|
168
|
+
__param(0, inject('SecurityPolicyFileReader')),
|
|
169
|
+
__param(1, inject('SecurityPolicyValidator')),
|
|
170
|
+
__param(2, inject('ISettingsRepository')),
|
|
171
|
+
__metadata("design:paramtypes", [SecurityPolicyFileReader,
|
|
172
|
+
SecurityPolicyValidator, Object])
|
|
173
|
+
], SecurityPolicyService);
|
|
174
|
+
export { SecurityPolicyService };
|