@macedon-technologies/batman 1.17.2 → 1.18.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/.jsii +205 -26
- package/.swamp.yaml +6 -0
- package/API.md +164 -1
- package/CLAUDE.md +44 -0
- package/architecture-rules/README.md +42 -0
- package/architecture-rules/check.ts +162 -0
- package/architecture-rules/rules.json +3 -0
- package/architecture-rules/tsconfig.json +14 -0
- package/attestation/manifest.ts +40 -0
- package/attestation/tsconfig.json +13 -0
- package/attestation/verify.ts +142 -0
- package/build-tools/scan-generated-workflows.ts +18 -11
- package/lib/Application.js +6 -1
- package/lib/BatmanProject.js +8 -2
- package/lib/BootcampProject.js +8 -2
- package/lib/CodeOwnersFile.js +1 -1
- package/lib/ProductionDeployWorkflow.js +1 -1
- package/lib/ProjenWorkflowHardening.d.ts +18 -0
- package/lib/ProjenWorkflowHardening.js +59 -0
- package/lib/SoftwareFactoryArchitectureRules.d.ts +10 -0
- package/lib/SoftwareFactoryArchitectureRules.js +245 -0
- package/lib/SoftwareFactoryAttestation.d.ts +18 -0
- package/lib/SoftwareFactoryAttestation.js +221 -0
- package/lib/SoftwareFactoryFiles.d.ts +45 -0
- package/lib/SoftwareFactoryFiles.js +102 -0
- package/lib/SoftwareFactoryModels.d.ts +25 -0
- package/lib/SoftwareFactoryModels.js +306 -0
- package/lib/SoftwareFactoryOpenSpecGates.d.ts +8 -0
- package/lib/SoftwareFactoryOpenSpecGates.js +75 -0
- package/lib/SoftwareFactoryWorkflows.d.ts +28 -0
- package/lib/SoftwareFactoryWorkflows.js +326 -0
- package/lib/StagingDeployWorkflow.js +1 -1
- package/lib/WorkflowActionVersions.d.ts +31 -1
- package/lib/WorkflowActionVersions.js +5 -1
- package/lib/WorkflowAutoDiscover.js +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.js +2 -1
- package/lib/utils.js +29 -1
- package/models/@goodcraft/github/platform-common-pr.yaml +10 -0
- package/models/@swamp/software-factory/platform-common-factory.yaml +240 -0
- package/models/@webframp/github/platform-common-issues.yaml +8 -0
- package/models/command/shell/platform-common-shell-architecture.yaml +8 -0
- package/models/command/shell/platform-common-shell-manifest.yaml +8 -0
- package/models/command/shell/platform-common-shell.yaml +8 -0
- package/openspec-gates/check-tasks-complete.ts +44 -0
- package/openspec-gates/tsconfig.json +13 -0
- package/package.json +6 -1
- package/workflows/workflow-openspec-plan-verify.yaml +51 -0
- package/workflows/workflow-openspec-tasks-verify.yaml +51 -0
- package/workflows/workflow-pre-pr-verify.yaml +118 -0
package/lib/BootcampProject.js
CHANGED
|
@@ -8,10 +8,11 @@ const BootcampApplication_1 = require("./BootcampApplication");
|
|
|
8
8
|
const CodeOwnersFile_1 = require("./CodeOwnersFile");
|
|
9
9
|
const DataDogAspectFile_1 = require("./DataDogAspectFile");
|
|
10
10
|
const GitHubRolesFile_1 = require("./GitHubRolesFile");
|
|
11
|
+
const SoftwareFactoryFiles_1 = require("./SoftwareFactoryFiles");
|
|
11
12
|
const utils_1 = require("./utils");
|
|
12
13
|
const ViteReactProject_1 = require("./ViteReactProject");
|
|
13
14
|
class BootcampProject extends awscdk_1.AwsCdkTypeScriptApp {
|
|
14
|
-
static [JSII_RTTI_SYMBOL_1] = { fqn: "@macedon-technologies/batman.BootcampProject", version: "1.
|
|
15
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "@macedon-technologies/batman.BootcampProject", version: "1.18.0" };
|
|
15
16
|
constructor(options) {
|
|
16
17
|
super({
|
|
17
18
|
...options,
|
|
@@ -96,6 +97,11 @@ class BootcampProject extends awscdk_1.AwsCdkTypeScriptApp {
|
|
|
96
97
|
additionalOwners: options.additionalCodeOwners,
|
|
97
98
|
});
|
|
98
99
|
new DataDogAspectFile_1.DataDogAspectFile(this);
|
|
100
|
+
new SoftwareFactoryFiles_1.SoftwareFactoryFiles(this, {
|
|
101
|
+
repoName: options.name,
|
|
102
|
+
baseBranch: options.defaultReleaseBranch,
|
|
103
|
+
actionVersions: options.actionVersions,
|
|
104
|
+
});
|
|
99
105
|
const viteReact = new ViteReactProject_1.ViteReactProject({
|
|
100
106
|
name: options.name,
|
|
101
107
|
defaultReleaseBranch: 'main',
|
|
@@ -118,4 +124,4 @@ class BootcampProject extends awscdk_1.AwsCdkTypeScriptApp {
|
|
|
118
124
|
}
|
|
119
125
|
}
|
|
120
126
|
exports.BootcampProject = BootcampProject;
|
|
121
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
127
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiQm9vdGNhbXBQcm9qZWN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL0Jvb3RjYW1wUHJvamVjdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBQUEsOENBQXdEO0FBQ3hELDhDQUFzRDtBQUV0RCwrREFBNEQ7QUFDNUQscURBQWtEO0FBQ2xELDJEQUF3RDtBQUN4RCx1REFBb0Q7QUFDcEQsaUVBQThEO0FBQzlELG1DQUF5QztBQUN6Qyx5REFBc0Q7QUFPdEQsTUFBYSxlQUFnQixTQUFRLDRCQUFtQjs7SUFDdEQsWUFBWSxPQUErQjtRQUN6QyxLQUFLLENBQUM7WUFDSixHQUFHLE9BQU87WUFDVixVQUFVLEVBQUUsT0FBTyxDQUFDLFVBQVUsSUFBSSxTQUFTO1lBQzNDLG9CQUFvQixFQUFFLE9BQU8sQ0FBQyxvQkFBb0IsSUFBSSxNQUFNO1lBQzVELElBQUksRUFBRSxPQUFPLENBQUMsSUFBSTtZQUNsQixVQUFVLEVBQUUsSUFBSTtZQUNoQixhQUFhLEVBQUUsS0FBSztZQUNwQixJQUFJLEVBQUU7Z0JBQ0osbUJBQW1CO2dCQUNuQixnQkFBZ0I7Z0JBQ2hCLFdBQVc7Z0JBQ1gsSUFBSTtnQkFDSixxQkFBcUI7Z0JBQ3JCLHNCQUFzQjtnQkFDdEIsMkJBQTJCO2dCQUMzQiwwQkFBMEI7Z0JBQzFCLG1DQUFtQztnQkFDbkMsY0FBYztnQkFDZCxpQ0FBaUM7Z0JBQ2pDLFNBQVM7Z0JBQ1QsaUJBQWlCO2dCQUNqQixhQUFhO2dCQUNiLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxFQUFFO2FBQ3RCO1lBQ0QsT0FBTyxFQUFFO2dCQUNQLHFCQUFxQjtnQkFDckIsU0FBUztnQkFDVCxjQUFjO2dCQUNkLHFDQUFxQztnQkFDckMsR0FBRyxPQUFPLENBQUMsT0FBTyxJQUFJLEVBQUU7YUFDekI7WUFDRCxTQUFTLEVBQUU7Z0JBQ1QsbURBQW1EO2dCQUNuRCxjQUFjO2dCQUNkLEdBQUcsT0FBTyxDQUFDLFNBQVMsSUFBSSxFQUFFO2FB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RTtZQUNqRixXQUFXLEVBQUUsSUFBSTtTQUNsQixDQUFDLENBQUM7SUFHTCxDQUFDOztBQTdISCwwQ0E4SEMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBBd3NDZGtUeXBlU2NyaXB0QXBwIH0gZnJvbSAncHJvamVuL2xpYi9hd3NjZGsnO1xuaW1wb3J0IHsgR2l0aHViQ3JlZGVudGlhbHMgfSBmcm9tICdwcm9qZW4vbGliL2dpdGh1Yic7XG5pbXBvcnQgeyBCYXRtYW5Qcm9qZWN0T3B0aW9ucyB9IGZyb20gJy4vQmF0bWFuUHJvamVjdCc7XG5pbXBvcnQgeyBCb290Y2FtcEFwcGxpY2F0aW9uIH0gZnJvbSAnLi9Cb290Y2FtcEFwcGxpY2F0aW9uJztcbmltcG9ydCB7IENvZGVPd25lcnNGaWxlIH0gZnJvbSAnLi9Db2RlT3duZXJzRmlsZSc7XG5pbXBvcnQgeyBEYXRhRG9nQXNwZWN0RmlsZSB9IGZyb20gJy4vRGF0YURvZ0FzcGVjdEZpbGUnO1xuaW1wb3J0IHsgR2l0SHViUm9sZXNGaWxlIH0gZnJvbSAnLi9HaXRIdWJSb2xlc0ZpbGUnO1xuaW1wb3J0IHsgU29mdHdhcmVGYWN0b3J5RmlsZXMgfSBmcm9tICcuL1NvZnR3YXJlRmFjdG9yeUZpbGVzJztcbmltcG9ydCB7IHJlYWRtZUNvbnRlbnRzIH0gZnJvbSAnLi91dGlscyc7XG5pbXBvcnQgeyBWaXRlUmVhY3RQcm9qZWN0IH0gZnJvbSAnLi9WaXRlUmVhY3RQcm9qZWN0JztcblxuXG5leHBvcnQgaW50ZXJmYWNlIEJvb3RjYW1wUHJvamVjdE9wdGlvbnMgZXh0ZW5kcyBCYXRtYW5Qcm9qZWN0T3B0aW9ucyB7XG5cbn1cblxuZXhwb3J0IGNsYXNzIEJvb3RjYW1wUHJvamVjdCBleHRlbmRzIEF3c0Nka1R5cGVTY3JpcHRBcHAge1xuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBCb290Y2FtcFByb2plY3RPcHRpb25zKSB7XG4gICAgc3VwZXIoe1xuICAgICAgLi4ub3B0aW9ucyxcbiAgICAgIGNka1ZlcnNpb246IG9wdGlvbnMuY2RrVmVyc2lvbiB8fCAnMi4yMjQuMCcsXG4gICAgICBkZWZhdWx0UmVsZWFzZUJyYW5jaDogb3B0aW9ucy5kZWZhdWx0UmVsZWFzZUJyYW5jaCB8fCAnbWFpbicsXG4gICAgICBuYW1lOiBvcHRpb25zLm5hbWUsXG4gICAgICBwcm9qZW5yY1RzOiB0cnVlLFxuICAgICAgYnVpbGRXb3JrZmxvdzogZmFsc2UsXG4gICAgICBkZXBzOiBbXG4gICAgICAgICdAdHlwZXMvYXdzLWxhbWJkYScsXG4gICAgICAgICdAdHlwZXMvZXhwcmVzcycsXG4gICAgICAgICdAdHlwZXMvcGcnLFxuICAgICAgICAncGcnLFxuICAgICAgICAnQGF3cy1zZGsvcmRzLXNpZ25lcicsXG4gICAgICAgICdAbWF0dGhld2JvbmlnL3NlY3JldCcsXG4gICAgICAgICdkYXRhZG9nLWNkay1jb25zdHJ1Y3RzLXYyJyxcbiAgICAgICAgJ0BjZGtsYWJzL2F3cy1sYW1iZGEtcnVzdCcsXG4gICAgICAgICdAYXdzLWxhbWJkYS1wb3dlcnRvb2xzL3BhcmFtZXRlcnMnLFxuICAgICAgICAnanNvbndlYnRva2VuJyxcbiAgICAgICAgJ0Bhd3Mtc2RrL2NsaWVudC1zZWNyZXRzLW1hbmFnZXInLFxuICAgICAgICAnZXhwcmVzcycsXG4gICAgICAgICdzZXJ2ZXJsZXNzLWh0dHAnLFxuICAgICAgICAnY2RrLXJkcy1zcWwnLFxuICAgICAgICAuLi5vcHRpb25zLmRlcHMgfHwgW10sXG4gICAgICBdLFxuICAgICAgZGV2RGVwczogW1xuICAgICAgICAnQHR5cGVzL2pzb253ZWJ0b2tlbicsXG4gICAgICAgICdub2RlbW9uJyxcbiAgICAgICAgJ2NvbmN1cnJlbnRseScsXG4gICAgICAgICdAbWFjZWRvbi10ZWNobm9sb2dpZXMvYmF0bWFuQF4xLjAuMCcsXG4gICAgICAgIC4uLm9wdGlvbnMuZGV2RGVwcyB8fCBbXSxcbiAgICAgIF0sXG4gICAgICBnaXRpZ25vcmU6IFtcbiAgICAgICAgJ3NyYy9jb25zdHJ1Y3RzL2hhbmRsZXIvY2xlcmstYXV0aG9yaXplci90YXJnZXQvKionLFxuICAgICAgICAnKiovLkRTX1N0b3JlJyxcbiAgICAgICAgLi4ub3B0aW9ucy5naXRpZ25vcmUgfHwgW10sXG4gICAgICBdLFxuICAgICAgdHNjb25maWc6IHtcbiAgICAgICAgLi4ub3B0aW9ucy50c2NvbmZpZyxcbiAgICAgICAgY29tcGlsZXJPcHRpb25zOiB7XG4gICAgICAgICAgLi4ub3B0aW9ucy50c2NvbmZpZz8uY29tcGlsZXJPcHRpb25zLFxuICAgICAgICAgIGlzb2xhdGVkTW9kdWxlczogdHJ1ZSxcbiAgICAgICAgICBhbGxvd0ltcG9ydGluZ1RzRXh0ZW5zaW9uczogdHJ1ZSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBzYW1wbGVDb2RlOiBmYWxzZSxcbiAgICAgIG1pbk5vZGVWZXJzaW9uOiBvcHRpb25zLm1pbk5vZGVWZXJzaW9uIHx8ICcyMicsXG4gICAgICBkZXBzVXBncmFkZU9wdGlvbnM6IHtcbiAgICAgICAgd29ya2Zsb3dPcHRpb25zOiB7XG4gICAgICAgICAgcHJvamVuQ3JlZGVudGlhbHM6IEdpdGh1YkNyZWRlbnRpYWxzLmZyb21QZXJzb25hbEFjY2Vzc1Rva2VuKHtcbiAgICAgICAgICAgIHNlY3JldDogJ0dJVEhVQl9UT0tFTicsXG4gICAgICAgICAgfSksXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgICAgcmVhZG1lOiB7XG4gICAgICAgIGNvbnRlbnRzOiByZWFkbWVDb250ZW50cyhvcHRpb25zLm5hbWUpLFxuICAgICAgfSxcbiAgICB9KTtcblxuXG4gICAgLy8gQ3JlYXRlIHN0YW5kYXJkIHByb2plY3QgZmlsZXNcbiAgICBjb25zdCBQUklNQVJZX0FDQ09VTlQgPSAnMDE1OTU1ODE3MjYzJztcbiAgICBjb25zdCBQUklNQVJZX1JFR0lPTiA9ICd1cy1lYXN0LTEnO1xuXG4gICAgbmV3IEJvb3RjYW1wQXBwbGljYXRpb24odGhpcywge1xuICAgICAgZ2l0aHViUmVwb3NpdG9yeTogYG1hY2Vkb24tdGVjaG5vbG9naWVzLyR7b3B0aW9ucy5uYW1lfWAsXG4gICAgICBkZXY6IHtcbiAgICAgICAgLi4ub3B0aW9ucy5kZXYsXG4gICAgICB9LFxuICAgICAgc3RhZ2luZzoge1xuICAgICAgICAuLi5vcHRpb25zLnN0YWdpbmcsXG4gICAgICB9LFxuICAgICAgcHJvZDoge1xuICAgICAgICAuLi5vcHRpb25zLmRldixcbiAgICAgIH0sXG4gICAgICBhZGRpdGlvbmFsVGFnczogb3B0aW9ucy5hZGRpdGlvbmFsVGFncyxcbiAgICAgIG44bldvcmtmbG93czogb3B0aW9ucy5uOG5Xb3JrZmxvd3MsXG4gICAgICBhY3Rpb25WZXJzaW9uczogb3B0aW9ucy5hY3Rpb25WZXJzaW9ucyxcbiAgICB9KTtcblxuICAgIG5ldyBHaXRIdWJSb2xlc0ZpbGUodGhpcywge1xuICAgICAgYWNjb3VudDogUFJJTUFSWV9BQ0NPVU5ULFxuICAgICAgcHJpbWFyeVJlZ2lvbjogUFJJTUFSWV9SRUdJT04sXG4gICAgfSk7XG5cbiAgICBuZXcgQ29kZU93bmVyc0ZpbGUodGhpcywge1xuICAgICAgYWRkaXRpb25hbE93bmVyczogb3B0aW9ucy5hZGRpdGlvbmFsQ29kZU93bmVycyxcbiAgICB9KTtcblxuICAgIG5ldyBEYXRhRG9nQXNwZWN0RmlsZSh0aGlzKTtcblxuICAgIG5ldyBTb2Z0d2FyZUZhY3RvcnlGaWxlcyh0aGlzLCB7XG4gICAgICByZXBvTmFtZTogb3B0aW9ucy5uYW1lLFxuICAgICAgYmFzZUJyYW5jaDogb3B0aW9ucy5kZWZhdWx0UmVsZWFzZUJyYW5jaCxcbiAgICAgIGFjdGlvblZlcnNpb25zOiBvcHRpb25zLmFjdGlvblZlcnNpb25zLFxuICAgIH0pO1xuXG4gICAgY29uc3Qgdml0ZVJlYWN0ID0gbmV3IFZpdGVSZWFjdFByb2plY3Qoe1xuICAgICAgbmFtZTogb3B0aW9ucy5uYW1lLFxuICAgICAgZGVmYXVsdFJlbGVhc2VCcmFuY2g6ICdtYWluJyxcbiAgICAgIHBhcmVudDogdGhpcyxcbiAgICAgIG91dGRpcjogJ3dlYicsXG4gICAgICBkZXBzOiBvcHRpb25zLndlYnNpdGVEZXBzLFxuICAgIH0pO1xuICAgIHZpdGVSZWFjdC5hZGRDb25maWdGaWVsZCgnc29tZXRoaW5nJywgJ251bWJlcicpO1xuICAgIHZpdGVSZWFjdC5hZGRDb25maWdGaWVsZCgnc29tZXRoaW5nRWxzZScsICdzdHJpbmcnKTtcblxuICAgIGNvbnN0IGNvbmN1cnJlbnRseSA9ICguLi5hcmdzOiBzdHJpbmdbXSkgPT4ge1xuICAgICAgcmV0dXJuIGBjb25jdXJyZW50bHkgJHthcmdzLm1hcChhID0+IGBcIiR7YX1cImApLmpvaW4oJyAnKX1gO1xuICAgIH07XG5cbiAgICB0aGlzLmFkZFRhc2soJ2RldicsIHtcbiAgICAgIGV4ZWM6IGNvbmN1cnJlbnRseShcbiAgICAgICAgJ25vZGVtb24gLS13YXRjaCAuL3NyYy9jb25zdHJ1Y3RzL2hhbmRsZXIgLS13YXRjaCAuL2xvY2FsL2Rldi50cyAuL2xvY2FsL2Rldi50cycsXG4gICAgICAgIHZpdGVSZWFjdC5kZXZDb21tYW5kLFxuICAgICAgKSxcbiAgICB9KTtcblxuICAgIHRoaXMuYWRkVGFzaygnY2RrOmRldicsIHtcbiAgICAgIGV4ZWM6ICdjZGsgLWEgXCJucHggdHMtbm9kZSAtUCB0c2NvbmZpZy5qc29uIC0tcHJlZmVyLXRzLWV4dHMgc3JjL0xvY2FsRGV2QXBwLnRzXCInLFxuICAgICAgcmVjZWl2ZUFyZ3M6IHRydWUsXG4gICAgfSk7XG5cblxuICB9XG59XG4iXX0=
|
package/lib/CodeOwnersFile.js
CHANGED
|
@@ -4,7 +4,7 @@ exports.CodeOwnersFile = void 0;
|
|
|
4
4
|
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
|
|
5
5
|
const projen_1 = require("projen");
|
|
6
6
|
class CodeOwnersFile extends projen_1.TextFile {
|
|
7
|
-
static [JSII_RTTI_SYMBOL_1] = { fqn: "@macedon-technologies/batman.CodeOwnersFile", version: "1.
|
|
7
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "@macedon-technologies/batman.CodeOwnersFile", version: "1.18.0" };
|
|
8
8
|
constructor(project, options = {}) {
|
|
9
9
|
const defaultOwners = ['* @macedon-technologies/platform'];
|
|
10
10
|
const allOwners = [...defaultOwners, ...(options.additionalOwners || [])];
|
|
@@ -7,7 +7,7 @@ const javascript_1 = require("projen/lib/javascript");
|
|
|
7
7
|
const utils_1 = require("./utils");
|
|
8
8
|
const WorkflowActionVersions_1 = require("./WorkflowActionVersions");
|
|
9
9
|
class ProductionDeployWorkflow extends projen_1.YamlFile {
|
|
10
|
-
static [JSII_RTTI_SYMBOL_1] = { fqn: "@macedon-technologies/batman.ProductionDeployWorkflow", version: "1.
|
|
10
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "@macedon-technologies/batman.ProductionDeployWorkflow", version: "1.18.0" };
|
|
11
11
|
constructor(project, options) {
|
|
12
12
|
const packageManager = project.package.packageManager;
|
|
13
13
|
const actionVersions = (0, WorkflowActionVersions_1.resolveActionVersions)(options.actionVersions);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AwsCdkTypeScriptApp } from 'projen/lib/awscdk';
|
|
2
|
+
import { WorkflowActionVersions } from './WorkflowActionVersions';
|
|
3
|
+
/**
|
|
4
|
+
* Hardens the GitHub Actions workflows that `AwsCdkTypeScriptApp` generates on its own
|
|
5
|
+
* (`upgrade.yml`, `pull-request-lint.yml`, ...) against the zizmor findings raised on
|
|
6
|
+
* consumer repos (e.g. macedon-technologies/exman#13).
|
|
7
|
+
*
|
|
8
|
+
* These workflows aren't hand-authored by this package the way `PrDeployWorkflow`/
|
|
9
|
+
* `PrCleanupWorkflow`/etc. are, so they can't be pinned by writing a literal SHA into a
|
|
10
|
+
* `uses:` string. projen exposes `project.github.actions` for exactly this case: every
|
|
11
|
+
* `uses:` rendered by a `GithubWorkflow`/`Job` (including projen's own built-in
|
|
12
|
+
* components) is resolved through it at synthesis time.
|
|
13
|
+
*
|
|
14
|
+
* `persist-credentials` and the `pull_request_target` trigger aren't covered by that
|
|
15
|
+
* registry (it only rewrites `uses:`), so those are corrected with a `JsonPatch` against
|
|
16
|
+
* the synthesized workflow file instead.
|
|
17
|
+
*/
|
|
18
|
+
export declare function hardenProjenGeneratedWorkflows(project: AwsCdkTypeScriptApp, actionVersions?: WorkflowActionVersions): void;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hardenProjenGeneratedWorkflows = hardenProjenGeneratedWorkflows;
|
|
4
|
+
const projen_1 = require("projen");
|
|
5
|
+
const WorkflowActionVersions_1 = require("./WorkflowActionVersions");
|
|
6
|
+
/**
|
|
7
|
+
* Hardens the GitHub Actions workflows that `AwsCdkTypeScriptApp` generates on its own
|
|
8
|
+
* (`upgrade.yml`, `pull-request-lint.yml`, ...) against the zizmor findings raised on
|
|
9
|
+
* consumer repos (e.g. macedon-technologies/exman#13).
|
|
10
|
+
*
|
|
11
|
+
* These workflows aren't hand-authored by this package the way `PrDeployWorkflow`/
|
|
12
|
+
* `PrCleanupWorkflow`/etc. are, so they can't be pinned by writing a literal SHA into a
|
|
13
|
+
* `uses:` string. projen exposes `project.github.actions` for exactly this case: every
|
|
14
|
+
* `uses:` rendered by a `GithubWorkflow`/`Job` (including projen's own built-in
|
|
15
|
+
* components) is resolved through it at synthesis time.
|
|
16
|
+
*
|
|
17
|
+
* `persist-credentials` and the `pull_request_target` trigger aren't covered by that
|
|
18
|
+
* registry (it only rewrites `uses:`), so those are corrected with a `JsonPatch` against
|
|
19
|
+
* the synthesized workflow file instead.
|
|
20
|
+
*/
|
|
21
|
+
function hardenProjenGeneratedWorkflows(project, actionVersions) {
|
|
22
|
+
const versions = (0, WorkflowActionVersions_1.resolveActionVersions)(actionVersions);
|
|
23
|
+
const github = project.github;
|
|
24
|
+
if (!github) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
// zizmor: unpinned-uses (high) — projen's built-in workflows reference these actions by
|
|
28
|
+
// mutable tag (e.g. `actions/checkout@v6`). Overriding by bare action name repoints every
|
|
29
|
+
// usage projen renders, without touching the hand-authored workflows above (which already
|
|
30
|
+
// embed a resolved SHA literal and never go through this registry). upload-artifact,
|
|
31
|
+
// download-artifact and action-semantic-pull-request weren't reported in #13, but are the
|
|
32
|
+
// same finding on the same two files, so they're pinned here too rather than left ticking.
|
|
33
|
+
github.actions.set('actions/checkout', versions.checkout);
|
|
34
|
+
github.actions.set('actions/setup-node', versions.setupNode);
|
|
35
|
+
github.actions.set('pnpm/action-setup', versions.pnpmActionSetup);
|
|
36
|
+
github.actions.set('actions/github-script', versions.githubScript);
|
|
37
|
+
github.actions.set('peter-evans/create-pull-request', versions.createPullRequest);
|
|
38
|
+
github.actions.set('actions/upload-artifact', versions.uploadArtifact);
|
|
39
|
+
github.actions.set('actions/download-artifact', versions.downloadArtifact);
|
|
40
|
+
github.actions.set('amannn/action-semantic-pull-request', versions.semanticPullRequest);
|
|
41
|
+
// zizmor: artipacked (low) — actions/checkout persists git credentials to disk by
|
|
42
|
+
// default. Neither of upgrade.yml's checkout steps need to push from that checkout
|
|
43
|
+
// (the "pr" job's push happens via peter-evans/create-pull-request with its own token).
|
|
44
|
+
const upgrade = github.tryFindWorkflow('upgrade');
|
|
45
|
+
upgrade?.file?.patch(projen_1.JsonPatch.add('/jobs/upgrade/steps/0/with', { 'persist-credentials': false }), projen_1.JsonPatch.add('/jobs/pr/steps/0/with', { 'persist-credentials': false }));
|
|
46
|
+
// zizmor: dangerous-triggers (high) — pull-request-lint.yml only validates the PR title;
|
|
47
|
+
// it doesn't need pull_request_target's access to secrets/write permissions against
|
|
48
|
+
// untrusted fork content. `pull_request` covers the same title-changed events without
|
|
49
|
+
// the risk. (If a consumer ever needs this check to comment on forked PRs, that consumer
|
|
50
|
+
// should override `pullRequestLintOptions` accordingly instead of reverting this globally.)
|
|
51
|
+
const pullRequestLint = github.tryFindWorkflow('pull-request-lint');
|
|
52
|
+
pullRequestLint?.file?.patch(projen_1.JsonPatch.replace('/on', {
|
|
53
|
+
pull_request: {
|
|
54
|
+
types: ['labeled', 'opened', 'synchronize', 'reopened', 'ready_for_review', 'edited'],
|
|
55
|
+
},
|
|
56
|
+
merge_group: {},
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUHJvamVuV29ya2Zsb3dIYXJkZW5pbmcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvUHJvamVuV29ya2Zsb3dIYXJkZW5pbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFtQkEsd0VBNkNDO0FBaEVELG1DQUFtQztBQUVuQyxxRUFBeUY7QUFFekY7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxTQUFnQiw4QkFBOEIsQ0FBQyxPQUE0QixFQUFFLGNBQXVDO0lBQ2xILE1BQU0sUUFBUSxHQUFHLElBQUEsOENBQXFCLEVBQUMsY0FBYyxDQUFDLENBQUM7SUFDdkQsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQztJQUM5QixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7UUFDWixPQUFPO0lBQ1QsQ0FBQztJQUVELHdGQUF3RjtJQUN4RiwwRkFBMEY7SUFDMUYsMEZBQTBGO0lBQzFGLHFGQUFxRjtJQUNyRiwwRkFBMEY7SUFDMUYsMkZBQTJGO0lBQzNGLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixFQUFFLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUMxRCxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQkFBb0IsRUFBRSxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDN0QsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLEVBQUUsUUFBUSxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQ2xFLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLHVCQUF1QixFQUFFLFFBQVEsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUNuRSxNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQ0FBaUMsRUFBRSxRQUFRLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUNsRixNQUFNLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyx5QkFBeUIsRUFBRSxRQUFRLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDdkUsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLEVBQUUsUUFBUSxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFDM0UsTUFBTSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMscUNBQXFDLEVBQUUsUUFBUSxDQUFDLG1CQUFtQixDQUFDLENBQUM7SUFFeEYsa0ZBQWtGO0lBQ2xGLG1GQUFtRjtJQUNuRix3RkFBd0Y7SUFDeEYsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLGVBQWUsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUNsRCxPQUFPLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FDbEIsa0JBQVMsQ0FBQyxHQUFHLENBQUMsNEJBQTRCLEVBQUUsRUFBRSxxQkFBcUIsRUFBRSxLQUFLLEVBQUUsQ0FBQyxFQUM3RSxrQkFBUyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsRUFBRSxFQUFFLHFCQUFxQixFQUFFLEtBQUssRUFBRSxDQUFDLENBQ3pFLENBQUM7SUFFRix5RkFBeUY7SUFDekYsb0ZBQW9GO0lBQ3BGLHNGQUFzRjtJQUN0Rix5RkFBeUY7SUFDekYsNEZBQTRGO0lBQzVGLE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxlQUFlLENBQUMsbUJBQW1CLENBQUMsQ0FBQztJQUNwRSxlQUFlLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FDMUIsa0JBQVMsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFO1FBQ3ZCLFlBQVksRUFBRTtZQUNaLEtBQUssRUFBRSxDQUFDLFNBQVMsRUFBRSxRQUFRLEVBQUUsYUFBYSxFQUFFLFVBQVUsRUFBRSxrQkFBa0IsRUFBRSxRQUFRLENBQUM7U0FDdEY7UUFDRCxXQUFXLEVBQUUsRUFBRTtLQUNoQixDQUFDLENBQ0gsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBKc29uUGF0Y2ggfSBmcm9tICdwcm9qZW4nO1xuaW1wb3J0IHsgQXdzQ2RrVHlwZVNjcmlwdEFwcCB9IGZyb20gJ3Byb2plbi9saWIvYXdzY2RrJztcbmltcG9ydCB7IHJlc29sdmVBY3Rpb25WZXJzaW9ucywgV29ya2Zsb3dBY3Rpb25WZXJzaW9ucyB9IGZyb20gJy4vV29ya2Zsb3dBY3Rpb25WZXJzaW9ucyc7XG5cbi8qKlxuICogSGFyZGVucyB0aGUgR2l0SHViIEFjdGlvbnMgd29ya2Zsb3dzIHRoYXQgYEF3c0Nka1R5cGVTY3JpcHRBcHBgIGdlbmVyYXRlcyBvbiBpdHMgb3duXG4gKiAoYHVwZ3JhZGUueW1sYCwgYHB1bGwtcmVxdWVzdC1saW50LnltbGAsIC4uLikgYWdhaW5zdCB0aGUgeml6bW9yIGZpbmRpbmdzIHJhaXNlZCBvblxuICogY29uc3VtZXIgcmVwb3MgKGUuZy4gbWFjZWRvbi10ZWNobm9sb2dpZXMvZXhtYW4jMTMpLlxuICpcbiAqIFRoZXNlIHdvcmtmbG93cyBhcmVuJ3QgaGFuZC1hdXRob3JlZCBieSB0aGlzIHBhY2thZ2UgdGhlIHdheSBgUHJEZXBsb3lXb3JrZmxvd2AvXG4gKiBgUHJDbGVhbnVwV29ya2Zsb3dgL2V0Yy4gYXJlLCBzbyB0aGV5IGNhbid0IGJlIHBpbm5lZCBieSB3cml0aW5nIGEgbGl0ZXJhbCBTSEEgaW50byBhXG4gKiBgdXNlczpgIHN0cmluZy4gcHJvamVuIGV4cG9zZXMgYHByb2plY3QuZ2l0aHViLmFjdGlvbnNgIGZvciBleGFjdGx5IHRoaXMgY2FzZTogZXZlcnlcbiAqIGB1c2VzOmAgcmVuZGVyZWQgYnkgYSBgR2l0aHViV29ya2Zsb3dgL2BKb2JgIChpbmNsdWRpbmcgcHJvamVuJ3Mgb3duIGJ1aWx0LWluXG4gKiBjb21wb25lbnRzKSBpcyByZXNvbHZlZCB0aHJvdWdoIGl0IGF0IHN5bnRoZXNpcyB0aW1lLlxuICpcbiAqIGBwZXJzaXN0LWNyZWRlbnRpYWxzYCBhbmQgdGhlIGBwdWxsX3JlcXVlc3RfdGFyZ2V0YCB0cmlnZ2VyIGFyZW4ndCBjb3ZlcmVkIGJ5IHRoYXRcbiAqIHJlZ2lzdHJ5IChpdCBvbmx5IHJld3JpdGVzIGB1c2VzOmApLCBzbyB0aG9zZSBhcmUgY29ycmVjdGVkIHdpdGggYSBgSnNvblBhdGNoYCBhZ2FpbnN0XG4gKiB0aGUgc3ludGhlc2l6ZWQgd29ya2Zsb3cgZmlsZSBpbnN0ZWFkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGFyZGVuUHJvamVuR2VuZXJhdGVkV29ya2Zsb3dzKHByb2plY3Q6IEF3c0Nka1R5cGVTY3JpcHRBcHAsIGFjdGlvblZlcnNpb25zPzogV29ya2Zsb3dBY3Rpb25WZXJzaW9ucyk6IHZvaWQge1xuICBjb25zdCB2ZXJzaW9ucyA9IHJlc29sdmVBY3Rpb25WZXJzaW9ucyhhY3Rpb25WZXJzaW9ucyk7XG4gIGNvbnN0IGdpdGh1YiA9IHByb2plY3QuZ2l0aHViO1xuICBpZiAoIWdpdGh1Yikge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIHppem1vcjogdW5waW5uZWQtdXNlcyAoaGlnaCkg4oCUIHByb2plbidzIGJ1aWx0LWluIHdvcmtmbG93cyByZWZlcmVuY2UgdGhlc2UgYWN0aW9ucyBieVxuICAvLyBtdXRhYmxlIHRhZyAoZS5nLiBgYWN0aW9ucy9jaGVja291dEB2NmApLiBPdmVycmlkaW5nIGJ5IGJhcmUgYWN0aW9uIG5hbWUgcmVwb2ludHMgZXZlcnlcbiAgLy8gdXNhZ2UgcHJvamVuIHJlbmRlcnMsIHdpdGhvdXQgdG91Y2hpbmcgdGhlIGhhbmQtYXV0aG9yZWQgd29ya2Zsb3dzIGFib3ZlICh3aGljaCBhbHJlYWR5XG4gIC8vIGVtYmVkIGEgcmVzb2x2ZWQgU0hBIGxpdGVyYWwgYW5kIG5ldmVyIGdvIHRocm91Z2ggdGhpcyByZWdpc3RyeSkuIHVwbG9hZC1hcnRpZmFjdCxcbiAgLy8gZG93bmxvYWQtYXJ0aWZhY3QgYW5kIGFjdGlvbi1zZW1hbnRpYy1wdWxsLXJlcXVlc3Qgd2VyZW4ndCByZXBvcnRlZCBpbiAjMTMsIGJ1dCBhcmUgdGhlXG4gIC8vIHNhbWUgZmluZGluZyBvbiB0aGUgc2FtZSB0d28gZmlsZXMsIHNvIHRoZXkncmUgcGlubmVkIGhlcmUgdG9vIHJhdGhlciB0aGFuIGxlZnQgdGlja2luZy5cbiAgZ2l0aHViLmFjdGlvbnMuc2V0KCdhY3Rpb25zL2NoZWNrb3V0JywgdmVyc2lvbnMuY2hlY2tvdXQpO1xuICBnaXRodWIuYWN0aW9ucy5zZXQoJ2FjdGlvbnMvc2V0dXAtbm9kZScsIHZlcnNpb25zLnNldHVwTm9kZSk7XG4gIGdpdGh1Yi5hY3Rpb25zLnNldCgncG5wbS9hY3Rpb24tc2V0dXAnLCB2ZXJzaW9ucy5wbnBtQWN0aW9uU2V0dXApO1xuICBnaXRodWIuYWN0aW9ucy5zZXQoJ2FjdGlvbnMvZ2l0aHViLXNjcmlwdCcsIHZlcnNpb25zLmdpdGh1YlNjcmlwdCk7XG4gIGdpdGh1Yi5hY3Rpb25zLnNldCgncGV0ZXItZXZhbnMvY3JlYXRlLXB1bGwtcmVxdWVzdCcsIHZlcnNpb25zLmNyZWF0ZVB1bGxSZXF1ZXN0KTtcbiAgZ2l0aHViLmFjdGlvbnMuc2V0KCdhY3Rpb25zL3VwbG9hZC1hcnRpZmFjdCcsIHZlcnNpb25zLnVwbG9hZEFydGlmYWN0KTtcbiAgZ2l0aHViLmFjdGlvbnMuc2V0KCdhY3Rpb25zL2Rvd25sb2FkLWFydGlmYWN0JywgdmVyc2lvbnMuZG93bmxvYWRBcnRpZmFjdCk7XG4gIGdpdGh1Yi5hY3Rpb25zLnNldCgnYW1hbm5uL2FjdGlvbi1zZW1hbnRpYy1wdWxsLXJlcXVlc3QnLCB2ZXJzaW9ucy5zZW1hbnRpY1B1bGxSZXF1ZXN0KTtcblxuICAvLyB6aXptb3I6IGFydGlwYWNrZWQgKGxvdykg4oCUIGFjdGlvbnMvY2hlY2tvdXQgcGVyc2lzdHMgZ2l0IGNyZWRlbnRpYWxzIHRvIGRpc2sgYnlcbiAgLy8gZGVmYXVsdC4gTmVpdGhlciBvZiB1cGdyYWRlLnltbCdzIGNoZWNrb3V0IHN0ZXBzIG5lZWQgdG8gcHVzaCBmcm9tIHRoYXQgY2hlY2tvdXRcbiAgLy8gKHRoZSBcInByXCIgam9iJ3MgcHVzaCBoYXBwZW5zIHZpYSBwZXRlci1ldmFucy9jcmVhdGUtcHVsbC1yZXF1ZXN0IHdpdGggaXRzIG93biB0b2tlbikuXG4gIGNvbnN0IHVwZ3JhZGUgPSBnaXRodWIudHJ5RmluZFdvcmtmbG93KCd1cGdyYWRlJyk7XG4gIHVwZ3JhZGU/LmZpbGU/LnBhdGNoKFxuICAgIEpzb25QYXRjaC5hZGQoJy9qb2JzL3VwZ3JhZGUvc3RlcHMvMC93aXRoJywgeyAncGVyc2lzdC1jcmVkZW50aWFscyc6IGZhbHNlIH0pLFxuICAgIEpzb25QYXRjaC5hZGQoJy9qb2JzL3ByL3N0ZXBzLzAvd2l0aCcsIHsgJ3BlcnNpc3QtY3JlZGVudGlhbHMnOiBmYWxzZSB9KSxcbiAgKTtcblxuICAvLyB6aXptb3I6IGRhbmdlcm91cy10cmlnZ2VycyAoaGlnaCkg4oCUIHB1bGwtcmVxdWVzdC1saW50LnltbCBvbmx5IHZhbGlkYXRlcyB0aGUgUFIgdGl0bGU7XG4gIC8vIGl0IGRvZXNuJ3QgbmVlZCBwdWxsX3JlcXVlc3RfdGFyZ2V0J3MgYWNjZXNzIHRvIHNlY3JldHMvd3JpdGUgcGVybWlzc2lvbnMgYWdhaW5zdFxuICAvLyB1bnRydXN0ZWQgZm9yayBjb250ZW50LiBgcHVsbF9yZXF1ZXN0YCBjb3ZlcnMgdGhlIHNhbWUgdGl0bGUtY2hhbmdlZCBldmVudHMgd2l0aG91dFxuICAvLyB0aGUgcmlzay4gKElmIGEgY29uc3VtZXIgZXZlciBuZWVkcyB0aGlzIGNoZWNrIHRvIGNvbW1lbnQgb24gZm9ya2VkIFBScywgdGhhdCBjb25zdW1lclxuICAvLyBzaG91bGQgb3ZlcnJpZGUgYHB1bGxSZXF1ZXN0TGludE9wdGlvbnNgIGFjY29yZGluZ2x5IGluc3RlYWQgb2YgcmV2ZXJ0aW5nIHRoaXMgZ2xvYmFsbHkuKVxuICBjb25zdCBwdWxsUmVxdWVzdExpbnQgPSBnaXRodWIudHJ5RmluZFdvcmtmbG93KCdwdWxsLXJlcXVlc3QtbGludCcpO1xuICBwdWxsUmVxdWVzdExpbnQ/LmZpbGU/LnBhdGNoKFxuICAgIEpzb25QYXRjaC5yZXBsYWNlKCcvb24nLCB7XG4gICAgICBwdWxsX3JlcXVlc3Q6IHtcbiAgICAgICAgdHlwZXM6IFsnbGFiZWxlZCcsICdvcGVuZWQnLCAnc3luY2hyb25pemUnLCAncmVvcGVuZWQnLCAncmVhZHlfZm9yX3JldmlldycsICdlZGl0ZWQnXSxcbiAgICAgIH0sXG4gICAgICBtZXJnZV9ncm91cDoge30sXG4gICAgfSksXG4gICk7XG59XG4iXX0=
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { NodeProject } from 'projen/lib/javascript';
|
|
2
|
+
/**
|
|
3
|
+
* The generic, data-driven architecture rule engine plus an empty seed
|
|
4
|
+
* rules.json. `check.ts`/`tsconfig.json`/`README.md` are managed (Batman
|
|
5
|
+
* owns the engine); `rules.json` is a `SampleFile` — each repo's own rules
|
|
6
|
+
* are data the team owns, not something Batman should overwrite.
|
|
7
|
+
*/
|
|
8
|
+
export declare class SoftwareFactoryArchitectureRules {
|
|
9
|
+
constructor(project: NodeProject);
|
|
10
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SoftwareFactoryArchitectureRules = void 0;
|
|
4
|
+
const projen_1 = require("projen");
|
|
5
|
+
/**
|
|
6
|
+
* The generic, data-driven architecture rule engine plus an empty seed
|
|
7
|
+
* rules.json. `check.ts`/`tsconfig.json`/`README.md` are managed (Batman
|
|
8
|
+
* owns the engine); `rules.json` is a `SampleFile` — each repo's own rules
|
|
9
|
+
* are data the team owns, not something Batman should overwrite.
|
|
10
|
+
*/
|
|
11
|
+
class SoftwareFactoryArchitectureRules {
|
|
12
|
+
constructor(project) {
|
|
13
|
+
new projen_1.TextFile(project, 'architecture-rules/check.ts', {
|
|
14
|
+
marker: true,
|
|
15
|
+
lines: [
|
|
16
|
+
'/**',
|
|
17
|
+
' * Generic architecture-rule engine. Rules live entirely in rules.json — this',
|
|
18
|
+
' * file only knows how to evaluate the check "types" that rules can declare.',
|
|
19
|
+
' * Add a new rule by adding a rules.json entry; add a new check type by adding',
|
|
20
|
+
' * a case in evaluateRule().',
|
|
21
|
+
' */',
|
|
22
|
+
"import * as fs from 'node:fs';",
|
|
23
|
+
"import * as path from 'node:path';",
|
|
24
|
+
"import rulesFile from './rules.json';",
|
|
25
|
+
'',
|
|
26
|
+
'interface ForbiddenImportCheck {',
|
|
27
|
+
" type: 'forbidden-import';",
|
|
28
|
+
' // Glob patterns (relative to repo root) selecting the files this rule inspects.',
|
|
29
|
+
' from: string[];',
|
|
30
|
+
' // Glob patterns (relative to repo root) that "from" files may not import from.',
|
|
31
|
+
' forbid: string[];',
|
|
32
|
+
'}',
|
|
33
|
+
'',
|
|
34
|
+
'interface Rule {',
|
|
35
|
+
' id: string;',
|
|
36
|
+
' description: string;',
|
|
37
|
+
' enabled: boolean;',
|
|
38
|
+
" severity: 'low' | 'medium' | 'high' | 'critical';",
|
|
39
|
+
' check: ForbiddenImportCheck;',
|
|
40
|
+
'}',
|
|
41
|
+
'',
|
|
42
|
+
'interface Violation {',
|
|
43
|
+
' ruleId: string;',
|
|
44
|
+
' severity: string;',
|
|
45
|
+
' message: string;',
|
|
46
|
+
'}',
|
|
47
|
+
'',
|
|
48
|
+
"const REPO_ROOT = path.resolve(__dirname, '..');",
|
|
49
|
+
"const IGNORED_DIRS = new Set(['node_modules', '.git', '.swamp', 'cdk.out', 'lib', 'build', 'dist']);",
|
|
50
|
+
'',
|
|
51
|
+
'// Minimal glob -> RegExp: supports "*", "**", "**/" and literal path segments.',
|
|
52
|
+
'// No new dependency for this — the only pattern shapes rules.json ever needs',
|
|
53
|
+
'// are directory-prefix globs like "src/domains/*/commands/**".',
|
|
54
|
+
'function globToRegExp(glob: string): RegExp {',
|
|
55
|
+
" let out = '';",
|
|
56
|
+
' for (let i = 0; i < glob.length; i++) {',
|
|
57
|
+
' const c = glob[i];',
|
|
58
|
+
" if (c === '*' && glob[i + 1] === '*') {",
|
|
59
|
+
' i++;',
|
|
60
|
+
" if (glob[i + 1] === '/') {",
|
|
61
|
+
" out += '(?:.*/)?';",
|
|
62
|
+
' i++;',
|
|
63
|
+
' } else {',
|
|
64
|
+
" out += '.*';",
|
|
65
|
+
' }',
|
|
66
|
+
" } else if (c === '*') {",
|
|
67
|
+
" out += '[^/]*';",
|
|
68
|
+
" } else if (c === '?') {",
|
|
69
|
+
" out += '[^/]';",
|
|
70
|
+
" } else if ('.+^${}()|[]\\\\'.includes(c)) {",
|
|
71
|
+
' out += `\\\\${c}`;',
|
|
72
|
+
' } else {',
|
|
73
|
+
' out += c;',
|
|
74
|
+
' }',
|
|
75
|
+
' }',
|
|
76
|
+
' return new RegExp(`^${out}$`);',
|
|
77
|
+
'}',
|
|
78
|
+
'',
|
|
79
|
+
'function matchesAny(relFile: string, globs: string[]): boolean {',
|
|
80
|
+
' return globs.some((glob) => globToRegExp(glob).test(relFile));',
|
|
81
|
+
'}',
|
|
82
|
+
'',
|
|
83
|
+
'function toRepoRelative(absPath: string): string {',
|
|
84
|
+
" return path.relative(REPO_ROOT, absPath).split(path.sep).join('/');",
|
|
85
|
+
'}',
|
|
86
|
+
'',
|
|
87
|
+
'function walk(dir: string, acc: string[] = []): string[] {',
|
|
88
|
+
' for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {',
|
|
89
|
+
' if (IGNORED_DIRS.has(entry.name)) continue;',
|
|
90
|
+
' const full = path.join(dir, entry.name);',
|
|
91
|
+
' if (entry.isDirectory()) {',
|
|
92
|
+
' walk(full, acc);',
|
|
93
|
+
" } else if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx'))) {",
|
|
94
|
+
' acc.push(full);',
|
|
95
|
+
' }',
|
|
96
|
+
' }',
|
|
97
|
+
' return acc;',
|
|
98
|
+
'}',
|
|
99
|
+
'',
|
|
100
|
+
"const RELATIVE_IMPORT_RE = /(?:import|export)\\s+(?:[^'\";]*?\\bfrom\\s+)?['\"](\\.[^'\"]+)['\"]/g;",
|
|
101
|
+
'',
|
|
102
|
+
'function findRelativeImports(source: string): string[] {',
|
|
103
|
+
' const specs: string[] = [];',
|
|
104
|
+
' RELATIVE_IMPORT_RE.lastIndex = 0;',
|
|
105
|
+
' let match: RegExpExecArray | null;',
|
|
106
|
+
' while ((match = RELATIVE_IMPORT_RE.exec(source))) {',
|
|
107
|
+
' specs.push(match[1]);',
|
|
108
|
+
' }',
|
|
109
|
+
' return specs;',
|
|
110
|
+
'}',
|
|
111
|
+
'',
|
|
112
|
+
'// An import spec resolves to a module, not a specific file extension, so a',
|
|
113
|
+
'// forbid glob is checked against the bare resolved path plus its .ts/index.ts',
|
|
114
|
+
'// variants.',
|
|
115
|
+
'function resolvedCandidates(fromFile: string, spec: string): string[] {',
|
|
116
|
+
' const resolved = toRepoRelative(path.normalize(path.join(path.dirname(fromFile), spec)));',
|
|
117
|
+
' return [resolved, `${resolved}.ts`, `${resolved}/index.ts`];',
|
|
118
|
+
'}',
|
|
119
|
+
'',
|
|
120
|
+
'function evaluateForbiddenImport(rule: Rule): Violation[] {',
|
|
121
|
+
' const { from, forbid } = rule.check;',
|
|
122
|
+
' if (from.length === 0 || forbid.length === 0) return [];',
|
|
123
|
+
'',
|
|
124
|
+
' const violations: Violation[] = [];',
|
|
125
|
+
' for (const file of walk(REPO_ROOT)) {',
|
|
126
|
+
' const relFile = toRepoRelative(file);',
|
|
127
|
+
' if (!matchesAny(relFile, from)) continue;',
|
|
128
|
+
'',
|
|
129
|
+
" const source = fs.readFileSync(file, 'utf8');",
|
|
130
|
+
' for (const spec of findRelativeImports(source)) {',
|
|
131
|
+
' const candidates = resolvedCandidates(file, spec);',
|
|
132
|
+
' if (candidates.some((candidate) => matchesAny(candidate, forbid))) {',
|
|
133
|
+
' violations.push({',
|
|
134
|
+
' ruleId: rule.id,',
|
|
135
|
+
' severity: rule.severity,',
|
|
136
|
+
' message: `${relFile} imports "${spec}", which resolves under a path forbidden by rule "${rule.id}"`,',
|
|
137
|
+
' });',
|
|
138
|
+
' }',
|
|
139
|
+
' }',
|
|
140
|
+
' }',
|
|
141
|
+
' return violations;',
|
|
142
|
+
'}',
|
|
143
|
+
'',
|
|
144
|
+
'function evaluateRule(rule: Rule): Violation[] {',
|
|
145
|
+
' switch (rule.check.type) {',
|
|
146
|
+
" case 'forbidden-import':",
|
|
147
|
+
' return evaluateForbiddenImport(rule);',
|
|
148
|
+
' default:',
|
|
149
|
+
' throw new Error(`architecture-rules: unknown check.type "${(rule.check as { type: string }).type}" on rule "${rule.id}"`);',
|
|
150
|
+
' }',
|
|
151
|
+
'}',
|
|
152
|
+
'',
|
|
153
|
+
'function main(): number {',
|
|
154
|
+
' const rules = (rulesFile as { rules: Rule[] }).rules;',
|
|
155
|
+
' let evaluated = 0;',
|
|
156
|
+
' let deferred = 0;',
|
|
157
|
+
' const violations: Violation[] = [];',
|
|
158
|
+
'',
|
|
159
|
+
' for (const rule of rules) {',
|
|
160
|
+
' if (!rule.enabled) {',
|
|
161
|
+
' deferred++;',
|
|
162
|
+
' console.log(`[deferred] ${rule.id}: ${rule.description}`);',
|
|
163
|
+
' continue;',
|
|
164
|
+
' }',
|
|
165
|
+
' evaluated++;',
|
|
166
|
+
' violations.push(...evaluateRule(rule));',
|
|
167
|
+
' }',
|
|
168
|
+
'',
|
|
169
|
+
' console.log(`\\narchitecture-rules: ${evaluated} rule(s) evaluated, ${deferred} deferred, ${violations.length} violation(s)`);',
|
|
170
|
+
' for (const violation of violations) {',
|
|
171
|
+
' console.error(` [${violation.severity}] ${violation.ruleId}: ${violation.message}`);',
|
|
172
|
+
' }',
|
|
173
|
+
'',
|
|
174
|
+
' return violations.length > 0 ? 1 : 0;',
|
|
175
|
+
'}',
|
|
176
|
+
'',
|
|
177
|
+
'process.exit(main());',
|
|
178
|
+
],
|
|
179
|
+
});
|
|
180
|
+
new projen_1.JsonFile(project, 'architecture-rules/tsconfig.json', {
|
|
181
|
+
marker: false,
|
|
182
|
+
obj: {
|
|
183
|
+
extends: '../tsconfig.json',
|
|
184
|
+
compilerOptions: {
|
|
185
|
+
noEmit: true,
|
|
186
|
+
rootDir: '.',
|
|
187
|
+
},
|
|
188
|
+
include: ['*.ts', '*.json'],
|
|
189
|
+
exclude: ['node_modules'],
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
new projen_1.TextFile(project, 'architecture-rules/README.md', {
|
|
193
|
+
marker: true,
|
|
194
|
+
lines: [
|
|
195
|
+
'# Architecture rules',
|
|
196
|
+
'',
|
|
197
|
+
'A data-driven registry of architectural constraints, enforced by',
|
|
198
|
+
'`pnpm validate:architecture` and run as part of the pre-PR verification',
|
|
199
|
+
'workflow (`workflows/workflow-pre-pr-verify.yaml`) before the swamp factory',
|
|
200
|
+
'opens a PR. New rules are new entries in `rules.json`, not new code — the',
|
|
201
|
+
'engine (`check.ts`) only needs a new case in `evaluateRule()` when a rule',
|
|
202
|
+
'needs a genuinely new kind of check.',
|
|
203
|
+
'',
|
|
204
|
+
'## Rule shape',
|
|
205
|
+
'',
|
|
206
|
+
'```json',
|
|
207
|
+
'{',
|
|
208
|
+
' "id": "unique-id",',
|
|
209
|
+
' "description": "What this enforces and why.",',
|
|
210
|
+
' "enabled": true,',
|
|
211
|
+
' "severity": "low" | "medium" | "high" | "critical",',
|
|
212
|
+
' "check": {',
|
|
213
|
+
' "type": "forbidden-import",',
|
|
214
|
+
' "from": ["glob patterns selecting files this rule inspects"],',
|
|
215
|
+
' "forbid": ["glob patterns those files may not import from"]',
|
|
216
|
+
' }',
|
|
217
|
+
'}',
|
|
218
|
+
'```',
|
|
219
|
+
'',
|
|
220
|
+
'`enabled: false` rules are skipped (reported as "deferred") rather than',
|
|
221
|
+
"evaluated — use this for a rule you've named and described but don't yet",
|
|
222
|
+
'have a concrete convention to check.',
|
|
223
|
+
'',
|
|
224
|
+
'## Current rules',
|
|
225
|
+
'',
|
|
226
|
+
'None yet — `rules.json` ships empty. Add rules as your domain module',
|
|
227
|
+
'conventions solidify (e.g. an event-sourced/CQRS module layout under',
|
|
228
|
+
'`src/domains/<name>/{commands,events,aggregates,projections}/`).',
|
|
229
|
+
'',
|
|
230
|
+
'## Adding a check type',
|
|
231
|
+
'',
|
|
232
|
+
'`forbidden-import` is the only implemented `check.type`. If a future rule',
|
|
233
|
+
'needs something it can\'t express (e.g. "every aggregate file must have a',
|
|
234
|
+
'matching events file"), add a new `type` value, a matching interface, and a',
|
|
235
|
+
'case in `evaluateRule()` in `check.ts` — keep the engine itself generic;',
|
|
236
|
+
'rule-specific knowledge belongs in `rules.json`.',
|
|
237
|
+
],
|
|
238
|
+
});
|
|
239
|
+
new projen_1.SampleFile(project, 'architecture-rules/rules.json', {
|
|
240
|
+
contents: JSON.stringify({ rules: [] }, null, 2) + '\n',
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
exports.SoftwareFactoryArchitectureRules = SoftwareFactoryArchitectureRules;
|
|
245
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU29mdHdhcmVGYWN0b3J5QXJjaGl0ZWN0dXJlUnVsZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvU29mdHdhcmVGYWN0b3J5QXJjaGl0ZWN0dXJlUnVsZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsbUNBQXdEO0FBR3hEOzs7OztHQUtHO0FBQ0gsTUFBYSxnQ0FBZ0M7SUFDM0MsWUFBWSxPQUFvQjtRQUM5QixJQUFJLGlCQUFRLENBQUMsT0FBTyxFQUFFLDZCQUE2QixFQUFFO1lBQ25ELE1BQU0sRUFBRSxJQUFJO1lBQ1osS0FBSyxFQUFFO2dCQUNMLEtBQUs7Z0JBQ0wsK0VBQStFO2dCQUMvRSw4RUFBOEU7Z0JBQzlFLGdGQUFnRjtnQkFDaEYsOEJBQThCO2dCQUM5QixLQUFLO2dCQUNMLGdDQUFnQztnQkFDaEMsb0NBQW9DO2dCQUNwQyx1Q0FBdUM7Z0JBQ3ZDLEVBQUU7Z0JBQ0Ysa0NBQWtDO2dCQUNsQyw2QkFBNkI7Z0JBQzdCLG9GQUFvRjtnQkFDcEYsbUJBQW1CO2dCQUNuQixtRkFBbUY7Z0JBQ25GLHFCQUFxQjtnQkFDckIsR0FBRztnQkFDSCxFQUFFO2dCQUNGLGtCQUFrQjtnQkFDbEIsZUFBZTtnQkFDZix3QkFBd0I7Z0JBQ3hCLHFCQUFxQjtnQkFDckIscURBQXFEO2dCQUNyRCxnQ0FBZ0M7Z0JBQ2hDLEdBQUc7Z0JBQ0gsRUFBRTtnQkFDRix1QkFBdUI7Z0JBQ3ZCLG1CQUFtQjtnQkFDbkIscUJBQXFCO2dCQUNyQixvQkFBb0I7Z0JBQ3BCLEdBQUc7Z0JBQ0gsRUFBRTtnQkFDRixrREFBa0Q7Z0JBQ2xELHNHQUFzRztnQkFDdEcsRUFBRTtnQkFDRixpRkFBaUY7Z0JBQ2pGLCtFQUErRTtnQkFDL0UsaUVBQWlFO2dCQUNqRSwrQ0FBK0M7Z0JBQy9DLGlCQUFpQjtnQkFDakIsMkNBQTJDO2dCQUMzQyx3QkFBd0I7Z0JBQ3hCLDZDQUE2QztnQkFDN0MsWUFBWTtnQkFDWixrQ0FBa0M7Z0JBQ2xDLDRC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QUMsT0FBTyxFQUFFLDhCQUE4QixFQUFFO1lBQ3BELE1BQU0sRUFBRSxJQUFJO1lBQ1osS0FBSyxFQUFFO2dCQUNMLHNCQUFzQjtnQkFDdEIsRUFBRTtnQkFDRixrRUFBa0U7Z0JBQ2xFLHlFQUF5RTtnQkFDekUsNkVBQTZFO2dCQUM3RSwyRUFBMkU7Z0JBQzNFLDJFQUEyRTtnQkFDM0Usc0NBQXNDO2dCQUN0QyxFQUFFO2dCQUNGLGVBQWU7Z0JBQ2YsRUFBRTtnQkFDRixTQUFTO2dCQUNULEdBQUc7Z0JBQ0gsc0JBQXNCO2dCQUN0QixpREFBaUQ7Z0JBQ2pELG9CQUFvQjtnQkFDcEIsdURBQXVEO2dCQUN2RCxjQUFjO2dCQUNkLGlDQUFpQztnQkFDakMsbUVBQW1FO2dCQUNuRSxpRUFBaUU7Z0JBQ2pFLEtBQUs7Z0JBQ0wsR0FBRztnQkFDSCxLQUFLO2dCQUNMLEVBQUU7Z0JBQ0YseUVBQXlFO2dCQUN6RSwwRUFBMEU7Z0JBQzFFLHNDQUFzQztnQkFDdEMsRUFBRTtnQkFDRixrQkFBa0I7Z0JBQ2xCLEVBQUU7Z0JBQ0Ysc0VBQXNFO2dCQUN0RSxzRUFBc0U7Z0JBQ3RFLGtFQUFrRTtnQkFDbEUsRUFBRTtnQkFDRix3QkFBd0I7Z0JBQ3hCLEVBQUU7Z0JBQ0YsMkVBQTJFO2dCQUMzRSwyRUFBMkU7Z0JBQzNFLDZFQUE2RTtnQkFDN0UsMEVBQTBFO2dCQUMxRSxrREFBa0Q7YUFDbkQ7U0FDRixDQUFDLENBQUM7UUFFSCxJQUFJLG1CQUFVLENBQUMsT0FBTyxFQUFFLCtCQUErQixFQUFFO1lBQ3ZELFFBQVEsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBRSxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsR0FBRyxJQUFJO1NBQ3hELENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRjtBQTNPRCw0RUEyT0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBKc29uRmlsZSwgU2FtcGxlRmlsZSwgVGV4dEZpbGUgfSBmcm9tICdwcm9qZW4nO1xuaW1wb3J0IHsgTm9kZVByb2plY3QgfSBmcm9tICdwcm9qZW4vbGliL2phdmFzY3JpcHQnO1xuXG4vKipcbiAqIFRoZSBnZW5lcmljLCBkYXRhLWRyaXZlbiBhcmNoaXRlY3R1cmUgcnVsZSBlbmdpbmUgcGx1cyBhbiBlbXB0eSBzZWVkXG4gKiBydWxlcy5qc29uLiBgY2hlY2sudHNgL2B0c2NvbmZpZy5qc29uYC9gUkVBRE1FLm1kYCBhcmUgbWFuYWdlZCAoQmF0bWFuXG4gKiBvd25zIHRoZSBlbmdpbmUpOyBgcnVsZXMuanNvbmAgaXMgYSBgU2FtcGxlRmlsZWAg4oCUIGVhY2ggcmVwbydzIG93biBydWxlc1xuICogYXJlIGRhdGEgdGhlIHRlYW0gb3ducywgbm90IHNvbWV0aGluZyBCYXRtYW4gc2hvdWxkIG92ZXJ3cml0ZS5cbiAqL1xuZXhwb3J0IGNsYXNzIFNvZnR3YXJlRmFjdG9yeUFyY2hpdGVjdHVyZVJ1bGVzIHtcbiAgY29uc3RydWN0b3IocHJvamVjdDogTm9kZVByb2plY3QpIHtcbiAgICBuZXcgVGV4dEZpbGUocHJvamVjdCwgJ2FyY2hpdGVjdHVyZS1ydWxlcy9jaGVjay50cycsIHtcbiAgICAgIG1hcmtlcjogdHJ1ZSxcbiAgICAgIGxpbmVzOiBbXG4gICAgICAgICcvKionLFxuICAgICAgICAnICogR2VuZXJpYyBhcmNoaXRlY3R1cmUtcnVsZSBlbmdpbmUuIFJ1bGVzIGxpdmUgZW50aXJlbHkgaW4gcnVsZXMuanNvbiDigJQgdGhpcycsXG4gICAgICAgICcgKiBmaWxlIG9ubHkga25vd3MgaG93IHRvIGV2YWx1YXRlIHRoZSBjaGVjayBcInR5cGVzXCIgdGhhdCBydWxlcyBjYW4gZGVjbGFyZS4nLFxuICAgICAgICAnICogQWRkIGEgbmV3IHJ1bGUgYnkgYWRkaW5nIGEgcnVsZXMuanNvbiBlbnRyeTsgYWRkIGEgbmV3IGNoZWNrIHR5cGUgYnkgYWRkaW5nJyxcbiAgICAgICAgJyAqIGEgY2FzZSBpbiBldmFsdWF0ZVJ1bGUoKS4nLFxuICAgICAgICAnICovJyxcbiAgICAgICAgXCJpbXBvcnQgKiBhcyBmcyBmcm9tICdub2RlOmZzJztcIixcbiAgICAgICAgXCJpbXBvcnQgKiBhcyBwYXRoIGZyb20gJ25vZGU6cGF0aCc7XCIsXG4gICAgICAgIFwiaW1wb3J0IHJ1bGVzRmlsZSBmcm9tICcuL3J1bGVzLmpzb24nO1wiLFxuICAgICAgICAnJyxcbiAgICAgICAgJ2ludGVyZmFjZSBGb3JiaWRkZW5JbXBvcnRDaGVjayB7JyxcbiAgICAgICAgXCIgIHR5cGU6ICdmb3JiaWRkZW4taW1wb3J0JztcIixcbiAgICAgICAgJyAgLy8gR2xvYiBwYXR0ZXJucyAocmVsYXRpdmUgdG8gcmVwbyByb290KSBzZWxlY3RpbmcgdGhlIGZpbGVzIHRoaXMgcnVsZSBpbnNwZWN0cy4nLFxuICAgICAgICAnICBmcm9tOiBzdHJpbmdbXTsnLFxuICAgICAgICAnICAvLyBHbG9iIHBhdHRlcm5zIChyZWxhdGl2ZSB0byByZXBvIHJvb3QpIHRoYXQgXCJmcm9tXCIgZmlsZXMgbWF5IG5vdCBpbXBvcnQgZnJvbS4nLFxuICAgICAgICAnICBmb3JiaWQ6IHN0cmluZ1tdOycsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgICdpbnRlcmZhY2UgUnVsZSB7JyxcbiAgICAgICAgJyAgaWQ6IHN0cmluZzsnLFxuICAgICAgICAnICBkZXNjcmlwdGlvbjogc3RyaW5nOycsXG4gICAgICAgICcgIGVuYWJsZWQ6IGJvb2xlYW47JyxcbiAgICAgICAgXCIgIHNldmVyaXR5OiAnbG93JyB8ICdtZWRpdW0nIHwgJ2hpZ2gnIHwgJ2NyaXRpY2FsJztcIixcbiAgICAgICAgJyAgY2hlY2s6IEZvcmJpZGRlbkltcG9ydENoZWNrOycsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgICdpbnRlcmZhY2UgVmlvbGF0aW9uIHsnLFxuICAgICAgICAnICBydWxlSWQ6IHN0cmluZzsnLFxuICAgICAgICAnICBzZXZlcml0eTogc3RyaW5nOycsXG4gICAgICAgICcgIG1lc3NhZ2U6IHN0cmluZzsnLFxuICAgICAgICAnfScsXG4gICAgICAgICcnLFxuICAgICAgICBcImNvbnN0IFJFUE9fUk9PVCA9IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICcuLicpO1wiLFxuICAgICAgICBcImNvbnN0IElHTk9SRURfRElSUyA9IG5ldyBTZXQoWydub2RlX21vZHVsZXMnLCAnLmdpdCcsICcuc3dhbXAnLCAnY2RrLm91dCcsICdsaWInLCAnYnVpbGQnLCAnZGlzdCddKTtcIixcbiAgICAgICAgJycsXG4gICAgICAgICcvLyBNaW5pbWFsIGdsb2IgLT4gUmVnRXhwOiBzdXBwb3J0cyBcIipcIiwgXCIqKlwiLCBcIioqL1wiIGFuZCBsaXRlcmFsIHBhdGggc2VnbWVudHMuJyxcbiAgICAgICAgJy8vIE5vIG5ldyBkZXBlbmRlbmN5IGZvciB0aGlzIOKAlCB0aGUgb25seSBwYXR0ZXJuIHNoYXBlcyBydWxlcy5qc29uIGV2ZXIgbmVlZHMnLFxuICAgICAgICAnLy8gYXJlIGRpcmVjdG9yeS1wcmVmaXggZ2xvYnMgbGlrZSBcInNyYy9kb21haW5zLyovY29tbWFuZHMvKipcIi4nLFxuICAgICAgICAnZnVuY3Rpb24gZ2xvYlRvUmVnRXhwKGdsb2I6IHN0cmluZyk6IFJlZ0V4cCB7JyxcbiAgICAgICAgXCIgIGxldCBvdXQgPSAnJztcIixcbiAgICAgICAgJyAgZm9yIChsZXQgaSA9IDA7IGkgPCBnbG9iLmxlbmd0aDsgaSsrKSB7JyxcbiAgICAgICAgJyAgICBjb25zdCBjID0gZ2xvYltpXTsnLFxuICAgICAgICBcIiAgICBpZiAoYyA9PT0gJyonICYmIGdsb2JbaSArIDFdID09PSAnKicpIHtcIixcbiAgICAgICAgJyAgICAgIGkrKzsnLFxuICAgICAgICBcIiAgICAgIGlmIChnbG9iW2kgKyAxXSA9PT0gJy8nKSB7XCIsXG4gICAgICAgIFwiICAgICAgICBvdXQgKz0gJyg/Oi4qLyk/JztcIixcbiAgICAgICAgJyAgICAgICAgaSsrOycsXG4gICAgICAgICcgICAgICB9IGVsc2UgeycsXG4gICAgICAgIFwiICAgICAgICBvdXQgKz0gJy4qJztcIixcbiAgICAgICAgJyAgICAgIH0nLFxuICAgICAgICBcIiAgICB9IGVsc2UgaWYgKGMgPT09ICcqJykge1wiLFxuICAgICAgICBcIiAgICAgIG91dCArPSAnW14vXSonO1wiLFxuICAgICAgICBcIiAgICB9IGVsc2UgaWYgKGMgPT09ICc/Jykge1wiLFxuICAgICAgICBcIiAgICAgIG91dCArPSAnW14vXSc7XCIsXG4gICAgICAgIFwiICAgIH0gZWxzZSBpZiAoJy4rXiR7fSgpfFtdXFxcXFxcXFwnLmluY2x1ZGVzKGMpKSB7XCIsXG4gICAgICAgICcgICAgICBvdXQgKz0gYFxcXFxcXFxcJHtjfWA7JyxcbiAgICAgICAgJyAgICB9IGVsc2UgeycsXG4gICAgICAgICcgICAgICBvdXQgKz0gYzsnLFxuICAgICAgICAnICAgIH0nLFxuICAgICAgICAnICB9JyxcbiAgICAgICAgJyAgcmV0dXJuIG5ldyBSZWdFeHAoYF4ke291dH0kYCk7JyxcbiAgICAgICAgJ30nLFxuICAgICAgICAnJyxcbiAgICAgICAgJ2Z1bmN0aW9uIG1hdGNoZXNBbnkocmVsRmlsZTogc3RyaW5nLCBnbG9iczogc3RyaW5nW10pOiBib29sZWFuIHsnLFxuICAgICAgICAnICByZXR1cm4gZ2xvYnMuc29tZSgoZ2xvYikgPT4gZ2xvYlRvUmVnRXhwKGdsb2IpLnRlc3QocmVsRmlsZSkpOycsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgICdmdW5jdGlvbiB0b1JlcG9SZWxhdGl2ZShhYnNQYXRoOiBzdHJpbmcpOiBzdHJpbmcgeycsXG4gICAgICAgIFwiICByZXR1cm4gcGF0aC5yZWxhdGl2ZShSRVBPX1JPT1QsIGFic1BhdGgpLnNwbGl0KHBhdGguc2VwKS5qb2luKCcvJyk7XCIsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgICdmdW5jdGlvbiB3YWxrKGRpcjogc3RyaW5nLCBhY2M6IHN0cmluZ1tdID0gW10pOiBzdHJpbmdbXSB7JyxcbiAgICAgICAgJyAgZm9yIChjb25zdCBlbnRyeSBvZiBmcy5yZWFkZGlyU3luYyhkaXIsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KSkgeycsXG4gICAgICAgICcgICAgaWYgKElHTk9SRURfRElSUy5oYXMoZW50cnkubmFtZSkpIGNvbnRpbnVlOycsXG4gICAgICAgICcgICAgY29uc3QgZnVsbCA9IHBhdGguam9pbihkaXIsIGVudHJ5Lm5hbWUpOycsXG4gICAgICAgICcgICAgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KCkpIHsnLFxuICAgICAgICAnICAgICAgd2FsayhmdWxsLCBhY2MpOycsXG4gICAgICAgIFwiICAgIH0gZWxzZSBpZiAoZW50cnkuaXNGaWxlKCkgJiYgKGVudHJ5Lm5hbWUuZW5kc1dpdGgoJy50cycpIHx8IGVudHJ5Lm5hbWUuZW5kc1dpdGgoJy50c3gnKSkpIHtcIixcbiAgICAgICAgJyAgICAgIGFjYy5wdXNoKGZ1bGwpOycsXG4gICAgICAgICcgICAgfScsXG4gICAgICAgICcgIH0nLFxuICAgICAgICAnICByZXR1cm4gYWNjOycsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgIFwiY29uc3QgUkVMQVRJVkVfSU1QT1JUX1JFID0gLyg/OmltcG9ydHxleHBvcnQpXFxcXHMrKD86W14nXFxcIjtdKj9cXFxcYmZyb21cXFxccyspP1snXFxcIl0oXFxcXC5bXidcXFwiXSspWydcXFwiXS9nO1wiLFxuICAgICAgICAnJyxcbiAgICAgICAgJ2Z1bmN0aW9uIGZpbmRSZWxhdGl2ZUltcG9ydHMoc291cmNlOiBzdHJpbmcpOiBzdHJpbmdbXSB7JyxcbiAgICAgICAgJyAgY29uc3Qgc3BlY3M6IHN0cmluZ1tdID0gW107JyxcbiAgICAgICAgJyAgUkVMQVRJVkVfSU1QT1JUX1JFLmxhc3RJbmRleCA9IDA7JyxcbiAgICAgICAgJyAgbGV0IG1hdGNoOiBSZWdFeHBFeGVjQXJyYXkgfCBudWxsOycsXG4gICAgICAgICcgIHdoaWxlICgobWF0Y2ggPSBSRUxBVElWRV9JTVBPUlRfUkUuZXhlYyhzb3VyY2UpKSkgeycsXG4gICAgICAgICcgICAgc3BlY3MucHVzaChtYXRjaFsxXSk7JyxcbiAgICAgICAgJyAgfScsXG4gICAgICAgICcgIHJldHVybiBzcGVjczsnLFxuICAgICAgICAnfScsXG4gICAgICAgICcnLFxuICAgICAgICAnLy8gQW4gaW1wb3J0IHNwZWMgcmVzb2x2ZXMgdG8gYSBtb2R1bGUsIG5vdCBhIHNwZWNpZmljIGZpbGUgZXh0ZW5zaW9uLCBzbyBhJyxcbiAgICAgICAgJy8vIGZvcmJpZCBnbG9iIGlzIGNoZWNrZWQgYWdhaW5zdCB0aGUgYmFyZSByZXNvbHZlZCBwYXRoIHBsdXMgaXRzIC50cy9pbmRleC50cycsXG4gICAgICAgICcvLyB2YXJpYW50cy4nLFxuICAgICAgICAnZnVuY3Rpb24gcmVzb2x2ZWRDYW5kaWRhdGVzKGZyb21GaWxlOiBzdHJpbmcsIHNwZWM6IHN0cmluZyk6IHN0cmluZ1tdIHsnLFxuICAgICAgICAnICBjb25zdCByZXNvbHZlZCA9IHRvUmVwb1JlbGF0aXZlKHBhdGgubm9ybWFsaXplKHBhdGguam9pbihwYXRoLmRpcm5hbWUoZnJvbUZpbGUpLCBzcGVjKSkpOycsXG4gICAgICAgICcgIHJldHVybiBbcmVzb2x2ZWQsIGAke3Jlc29sdmVkfS50c2AsIGAke3Jlc29sdmVkfS9pbmRleC50c2BdOycsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgICdmdW5jdGlvbiBldmFsdWF0ZUZvcmJpZGRlbkltcG9ydChydWxlOiBSdWxlKTogVmlvbGF0aW9uW10geycsXG4gICAgICAgICcgIGNvbnN0IHsgZnJvbSwgZm9yYmlkIH0gPSBydWxlLmNoZWNrOycsXG4gICAgICAgICcgIGlmIChmcm9tLmxlbmd0aCA9PT0gMCB8fCBmb3JiaWQubGVuZ3RoID09PSAwKSByZXR1cm4gW107JyxcbiAgICAgICAgJycsXG4gICAgICAgICcgIGNvbnN0IHZpb2xhdGlvbnM6IFZpb2xhdGlvbltdID0gW107JyxcbiAgICAgICAgJyAgZm9yIChjb25zdCBmaWxlIG9mIHdhbGsoUkVQT19ST09UKSkgeycsXG4gICAgICAgICcgICAgY29uc3QgcmVsRmlsZSA9IHRvUmVwb1JlbGF0aXZlKGZpbGUpOycsXG4gICAgICAgICcgICAgaWYgKCFtYXRjaGVzQW55KHJlbEZpbGUsIGZyb20pKSBjb250aW51ZTsnLFxuICAgICAgICAnJyxcbiAgICAgICAgXCIgICAgY29uc3Qgc291cmNlID0gZnMucmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4Jyk7XCIsXG4gICAgICAgICcgICAgZm9yIChjb25zdCBzcGVjIG9mIGZpbmRSZWxhdGl2ZUltcG9ydHMoc291cmNlKSkgeycsXG4gICAgICAgICcgICAgICBjb25zdCBjYW5kaWRhdGVzID0gcmVzb2x2ZWRDYW5kaWRhdGVzKGZpbGUsIHNwZWMpOycsXG4gICAgICAgICcgICAgICBpZiAoY2FuZGlkYXRlcy5zb21lKChjYW5kaWRhdGUpID0+IG1hdGNoZXNBbnkoY2FuZGlkYXRlLCBmb3JiaWQpKSkgeycsXG4gICAgICAgICcgICAgICAgIHZpb2xhdGlvbnMucHVzaCh7JyxcbiAgICAgICAgJyAgICAgICAgICBydWxlSWQ6IHJ1bGUuaWQsJyxcbiAgICAgICAgJyAgICAgICAgICBzZXZlcml0eTogcnVsZS5zZXZlcml0eSwnLFxuICAgICAgICAnICAgICAgICAgIG1lc3NhZ2U6IGAke3JlbEZpbGV9IGltcG9ydHMgXCIke3NwZWN9XCIsIHdoaWNoIHJlc29sdmVzIHVuZGVyIGEgcGF0aCBmb3JiaWRkZW4gYnkgcnVsZSBcIiR7cnVsZS5pZH1cImAsJyxcbiAgICAgICAgJyAgICAgICAgfSk7JyxcbiAgICAgICAgJyAgICAgIH0nLFxuICAgICAgICAnICAgIH0nLFxuICAgICAgICAnICB9JyxcbiAgICAgICAgJyAgcmV0dXJuIHZpb2xhdGlvbnM7JyxcbiAgICAgICAgJ30nLFxuICAgICAgICAnJyxcbiAgICAgICAgJ2Z1bmN0aW9uIGV2YWx1YXRlUnVsZShydWxlOiBSdWxlKTogVmlvbGF0aW9uW10geycsXG4gICAgICAgICcgIHN3aXRjaCAocnVsZS5jaGVjay50eXBlKSB7JyxcbiAgICAgICAgXCIgICAgY2FzZSAnZm9yYmlkZGVuLWltcG9ydCc6XCIsXG4gICAgICAgICcgICAgICByZXR1cm4gZXZhbHVhdGVGb3JiaWRkZW5JbXBvcnQocnVsZSk7JyxcbiAgICAgICAgJyAgICBkZWZhdWx0OicsXG4gICAgICAgICcgICAgICB0aHJvdyBuZXcgRXJyb3IoYGFyY2hpdGVjdHVyZS1ydWxlczogdW5rbm93biBjaGVjay50eXBlIFwiJHsocnVsZS5jaGVjayBhcyB7IHR5cGU6IHN0cmluZyB9KS50eXBlfVwiIG9uIHJ1bGUgXCIke3J1bGUuaWR9XCJgKTsnLFxuICAgICAgICAnICB9JyxcbiAgICAgICAgJ30nLFxuICAgICAgICAnJyxcbiAgICAgICAgJ2Z1bmN0aW9uIG1haW4oKTogbnVtYmVyIHsnLFxuICAgICAgICAnICBjb25zdCBydWxlcyA9IChydWxlc0ZpbGUgYXMgeyBydWxlczogUnVsZVtdIH0pLnJ1bGVzOycsXG4gICAgICAgICcgIGxldCBldmFsdWF0ZWQgPSAwOycsXG4gICAgICAgICcgIGxldCBkZWZlcnJlZCA9IDA7JyxcbiAgICAgICAgJyAgY29uc3QgdmlvbGF0aW9uczogVmlvbGF0aW9uW10gPSBbXTsnLFxuICAgICAgICAnJyxcbiAgICAgICAgJyAgZm9yIChjb25zdCBydWxlIG9mIHJ1bGVzKSB7JyxcbiAgICAgICAgJyAgICBpZiAoIXJ1bGUuZW5hYmxlZCkgeycsXG4gICAgICAgICcgICAgICBkZWZlcnJlZCsrOycsXG4gICAgICAgICcgICAgICBjb25zb2xlLmxvZyhgW2RlZmVycmVkXSAke3J1bGUuaWR9OiAke3J1bGUuZGVzY3JpcHRpb259YCk7JyxcbiAgICAgICAgJyAgICAgIGNvbnRpbnVlOycsXG4gICAgICAgICcgICAgfScsXG4gICAgICAgICcgICAgZXZhbHVhdGVkKys7JyxcbiAgICAgICAgJyAgICB2aW9sYXRpb25zLnB1c2goLi4uZXZhbHVhdGVSdWxlKHJ1bGUpKTsnLFxuICAgICAgICAnICB9JyxcbiAgICAgICAgJycsXG4gICAgICAgICcgIGNvbnNvbGUubG9nKGBcXFxcbmFyY2hpdGVjdHVyZS1ydWxlczogJHtldmFsdWF0ZWR9IHJ1bGUocykgZXZhbHVhdGVkLCAke2RlZmVycmVkfSBkZWZlcnJlZCwgJHt2aW9sYXRpb25zLmxlbmd0aH0gdmlvbGF0aW9uKHMpYCk7JyxcbiAgICAgICAgJyAgZm9yIChjb25zdCB2aW9sYXRpb24gb2YgdmlvbGF0aW9ucykgeycsXG4gICAgICAgICcgICAgY29uc29sZS5lcnJvcihgICBbJHt2aW9sYXRpb24uc2V2ZXJpdHl9XSAke3Zpb2xhdGlvbi5ydWxlSWR9OiAke3Zpb2xhdGlvbi5tZXNzYWdlfWApOycsXG4gICAgICAgICcgIH0nLFxuICAgICAgICAnJyxcbiAgICAgICAgJyAgcmV0dXJuIHZpb2xhdGlvbnMubGVuZ3RoID4gMCA/IDEgOiAwOycsXG4gICAgICAgICd9JyxcbiAgICAgICAgJycsXG4gICAgICAgICdwcm9jZXNzLmV4aXQobWFpbigpKTsnLFxuICAgICAgXSxcbiAgICB9KTtcblxuICAgIG5ldyBKc29uRmlsZShwcm9qZWN0LCAnYXJjaGl0ZWN0dXJlLXJ1bGVzL3RzY29uZmlnLmpzb24nLCB7XG4gICAgICBtYXJrZXI6IGZhbHNlLFxuICAgICAgb2JqOiB7XG4gICAgICAgIGV4dGVuZHM6ICcuLi90c2NvbmZpZy5qc29uJyxcbiAgICAgICAgY29tcGlsZXJPcHRpb25zOiB7XG4gICAgICAgICAgbm9FbWl0OiB0cnVlLFxuICAgICAgICAgIHJvb3REaXI6ICcuJyxcbiAgICAgICAgfSxcbiAgICAgICAgaW5jbHVkZTogWycqLnRzJywgJyouanNvbiddLFxuICAgICAgICBleGNsdWRlOiBbJ25vZGVfbW9kdWxlcyddLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIG5ldyBUZXh0RmlsZShwcm9qZWN0LCAnYXJjaGl0ZWN0dXJlLXJ1bGVzL1JFQURNRS5tZCcsIHtcbiAgICAgIG1hcmtlcjogdHJ1ZSxcbiAgICAgIGxpbmVzOiBbXG4gICAgICAgICcjIEFyY2hpdGVjdHVyZSBydWxlcycsXG4gICAgICAgICcnLFxuICAgICAgICAnQSBkYXRhLWRyaXZlbiByZWdpc3RyeSBvZiBhcmNoaXRlY3R1cmFsIGNvbnN0cmFpbnRzLCBlbmZvcmNlZCBieScsXG4gICAgICAgICdgcG5wbSB2YWxpZGF0ZTphcmNoaXRlY3R1cmVgIGFuZCBydW4gYXMgcGFydCBvZiB0aGUgcHJlLVBSIHZlcmlmaWNhdGlvbicsXG4gICAgICAgICd3b3JrZmxvdyAoYHdvcmtmbG93cy93b3JrZmxvdy1wcmUtcHItdmVyaWZ5LnlhbWxgKSBiZWZvcmUgdGhlIHN3YW1wIGZhY3RvcnknLFxuICAgICAgICAnb3BlbnMgYSBQUi4gTmV3IHJ1bGVzIGFyZSBuZXcgZW50cmllcyBpbiBgcnVsZXMuanNvbmAsIG5vdCBuZXcgY29kZSDigJQgdGhlJyxcbiAgICAgICAgJ2VuZ2luZSAoYGNoZWNrLnRzYCkgb25seSBuZWVkcyBhIG5ldyBjYXNlIGluIGBldmFsdWF0ZVJ1bGUoKWAgd2hlbiBhIHJ1bGUnLFxuICAgICAgICAnbmVlZHMgYSBnZW51aW5lbHkgbmV3IGtpbmQgb2YgY2hlY2suJyxcbiAgICAgICAgJycsXG4gICAgICAgICcjIyBSdWxlIHNoYXBlJyxcbiAgICAgICAgJycsXG4gICAgICAgICdgYGBqc29uJyxcbiAgICAgICAgJ3snLFxuICAgICAgICAnICBcImlkXCI6IFwidW5pcXVlLWlkXCIsJyxcbiAgICAgICAgJyAgXCJkZXNjcmlwdGlvblwiOiBcIldoYXQgdGhpcyBlbmZvcmNlcyBhbmQgd2h5LlwiLCcsXG4gICAgICAgICcgIFwiZW5hYmxlZFwiOiB0cnVlLCcsXG4gICAgICAgICcgIFwic2V2ZXJpdHlcIjogXCJsb3dcIiB8IFwibWVkaXVtXCIgfCBcImhpZ2hcIiB8IFwiY3JpdGljYWxcIiwnLFxuICAgICAgICAnICBcImNoZWNrXCI6IHsnLFxuICAgICAgICAnICAgIFwidHlwZVwiOiBcImZvcmJpZGRlbi1pbXBvcnRcIiwnLFxuICAgICAgICAnICAgIFwiZnJvbVwiOiBbXCJnbG9iIHBhdHRlcm5zIHNlbGVjdGluZyBmaWxlcyB0aGlzIHJ1bGUgaW5zcGVjdHNcIl0sJyxcbiAgICAgICAgJyAgICBcImZvcmJpZFwiOiBbXCJnbG9iIHBhdHRlcm5zIHRob3NlIGZpbGVzIG1heSBub3QgaW1wb3J0IGZyb21cIl0nLFxuICAgICAgICAnICB9JyxcbiAgICAgICAgJ30nLFxuICAgICAgICAnYGBgJyxcbiAgICAgICAgJycsXG4gICAgICAgICdgZW5hYmxlZDogZmFsc2VgIHJ1bGVzIGFyZSBza2lwcGVkIChyZXBvcnRlZCBhcyBcImRlZmVycmVkXCIpIHJhdGhlciB0aGFuJyxcbiAgICAgICAgXCJldmFsdWF0ZWQg4oCUIHVzZSB0aGlzIGZvciBhIHJ1bGUgeW91J3ZlIG5hbWVkIGFuZCBkZXNjcmliZWQgYnV0IGRvbid0IHlldFwiLFxuICAgICAgICAnaGF2ZSBhIGNvbmNyZXRlIGNvbnZlbnRpb24gdG8gY2hlY2suJyxcbiAgICAgICAgJycsXG4gICAgICAgICcjIyBDdXJyZW50IHJ1bGVzJyxcbiAgICAgICAgJycsXG4gICAgICAgICdOb25lIHlldCDigJQgYHJ1bGVzLmpzb25gIHNoaXBzIGVtcHR5LiBBZGQgcnVsZXMgYXMgeW91ciBkb21haW4gbW9kdWxlJyxcbiAgICAgICAgJ2NvbnZlbnRpb25zIHNvbGlkaWZ5IChlLmcuIGFuIGV2ZW50LXNvdXJjZWQvQ1FSUyBtb2R1bGUgbGF5b3V0IHVuZGVyJyxcbiAgICAgICAgJ2BzcmMvZG9tYWlucy88bmFtZT4ve2NvbW1hbmRzLGV2ZW50cyxhZ2dyZWdhdGVzLHByb2plY3Rpb25zfS9gKS4nLFxuICAgICAgICAnJyxcbiAgICAgICAgJyMjIEFkZGluZyBhIGNoZWNrIHR5cGUnLFxuICAgICAgICAnJyxcbiAgICAgICAgJ2Bmb3JiaWRkZW4taW1wb3J0YCBpcyB0aGUgb25seSBpbXBsZW1lbnRlZCBgY2hlY2sudHlwZWAuIElmIGEgZnV0dXJlIHJ1bGUnLFxuICAgICAgICAnbmVlZHMgc29tZXRoaW5nIGl0IGNhblxcJ3QgZXhwcmVzcyAoZS5nLiBcImV2ZXJ5IGFnZ3JlZ2F0ZSBmaWxlIG11c3QgaGF2ZSBhJyxcbiAgICAgICAgJ21hdGNoaW5nIGV2ZW50cyBmaWxlXCIpLCBhZGQgYSBuZXcgYHR5cGVgIHZhbHVlLCBhIG1hdGNoaW5nIGludGVyZmFjZSwgYW5kIGEnLFxuICAgICAgICAnY2FzZSBpbiBgZXZhbHVhdGVSdWxlKClgIGluIGBjaGVjay50c2Ag4oCUIGtlZXAgdGhlIGVuZ2luZSBpdHNlbGYgZ2VuZXJpYzsnLFxuICAgICAgICAncnVsZS1zcGVjaWZpYyBrbm93bGVkZ2UgYmVsb25ncyBpbiBgcnVsZXMuanNvbmAuJyxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBuZXcgU2FtcGxlRmlsZShwcm9qZWN0LCAnYXJjaGl0ZWN0dXJlLXJ1bGVzL3J1bGVzLmpzb24nLCB7XG4gICAgICBjb250ZW50czogSlNPTi5zdHJpbmdpZnkoeyBydWxlczogW10gfSwgbnVsbCwgMikgKyAnXFxuJyxcbiAgICB9KTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { NodeProject } from 'projen/lib/javascript';
|
|
2
|
+
export interface SoftwareFactoryAttestationOptions {
|
|
3
|
+
/**
|
|
4
|
+
* The bare repo name, used to point MANIFEST_FILES at
|
|
5
|
+
* `models/@swamp/software-factory/<repoName>-factory.yaml`.
|
|
6
|
+
*/
|
|
7
|
+
readonly repoName: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The tamper-evident PR attestation mechanism: `manifest.ts` hashes the
|
|
11
|
+
* files that determine what pre-pr-verify checked, `verify.ts` re-checks
|
|
12
|
+
* those hashes (plus commit/status/freshness) against a PR's embedded
|
|
13
|
+
* `<!-- attestation-manifest -->` block at merge time. Fully generic engine
|
|
14
|
+
* logic — Batman owns and evolves these, so both are managed `TextFile`s.
|
|
15
|
+
*/
|
|
16
|
+
export declare class SoftwareFactoryAttestation {
|
|
17
|
+
constructor(project: NodeProject, options: SoftwareFactoryAttestationOptions);
|
|
18
|
+
}
|