@continuous-excellence/ze-great-dashboard-aws 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/bootstrap/github-oidc-v2.yml +15 -0
- package/dist/bootstrap.d.ts +2 -0
- package/dist/cli.js +63 -7
- package/dist/doctor.d.ts +2 -0
- package/dist/guided.d.ts +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +22 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,6 +8,11 @@ It does not create a public endpoint, choose an authentication policy, create a
|
|
|
8
8
|
secret value, or own consumer AWS infrastructure. You provide the protected gateway and complete the
|
|
9
9
|
administrator-owned bootstrap process first.
|
|
10
10
|
|
|
11
|
+
For a deployment workflow that verifies a consumer-owned gateway stack, configure
|
|
12
|
+
`--consumer-gateway-stack gateway-stack-name` during `bootstrap init`. The GitHub OIDC v2 role then
|
|
13
|
+
gets only `cloudformation:DescribeStacks` for that exact stack; the package still does not create,
|
|
14
|
+
invoke, or authenticate the gateway.
|
|
15
|
+
|
|
11
16
|
## Prerequisites
|
|
12
17
|
|
|
13
18
|
You need Node.js 22+, npm, the AWS CLI, `jq`, and one AWS Region for the artifact bucket, Lambda,
|
|
@@ -69,6 +74,11 @@ npm exec -- ze-great-dashboard-aws doctor \
|
|
|
69
74
|
--region us-east-1
|
|
70
75
|
```
|
|
71
76
|
|
|
77
|
+
If you retain a captured GitHub OIDC stack, add `--github-oidc-stack-json
|
|
78
|
+
github-oidc-deployed-stack.json` to have the doctor warn when the installed package contains a
|
|
79
|
+
newer bootstrap template revision. The warning is advisory and does not make the application
|
|
80
|
+
deployment perform bootstrap changes.
|
|
81
|
+
|
|
72
82
|
Package the release. This validates the board and writes `lambda.zip`, `release.json`, and
|
|
73
83
|
`template.yml` to the output directory:
|
|
74
84
|
|
|
@@ -117,6 +127,12 @@ does not grant public Lambda invoke permission.
|
|
|
117
127
|
To upgrade, install a newer exact package version and repeat package, upload, and deploy. A change to
|
|
118
128
|
`board.yaml` follows the same path; it does not require a package change.
|
|
119
129
|
|
|
130
|
+
After upgrading, also check the [bootstrap upgrade guidance](https://github.com/robertfmurdock/ze-great-dashboard/blob/main/docs/aws-bootstrap.md#check-the-bootstrap-template-on-package-upgrades).
|
|
131
|
+
Compatible releases may add optional bootstrap capabilities without changing the contract version.
|
|
132
|
+
If your workflow verifies a consumer-owned gateway stack, add `githubOidc.consumerGatewayStackName`
|
|
133
|
+
to the reviewed manifest and update the GitHub OIDC stack; other consumers do not need to rerun
|
|
134
|
+
bootstrap.
|
|
135
|
+
|
|
120
136
|
Tokens belong in runtime secret handling, never in board YAML, `aws-dashboard-parameters.json`, or
|
|
121
137
|
the generated ZIP. See [runtime secrets](https://github.com/robertfmurdock/ze-great-dashboard/blob/main/docs/aws-setup.md#runtime-secrets)
|
|
122
138
|
for the supported secret reference and integration boundary.
|
|
@@ -8,9 +8,16 @@ Parameters:
|
|
|
8
8
|
GitHubRepositoryId: { Type: String, Description: Immutable numeric GitHub repository id }
|
|
9
9
|
GitHubEnvironment: { Type: String, Description: Protected GitHub Environment name }
|
|
10
10
|
ApplicationStackName: { Type: String }
|
|
11
|
+
ConsumerGatewayStackName:
|
|
12
|
+
Type: String
|
|
13
|
+
Default: ''
|
|
14
|
+
Description: Optional consumer-owned gateway stack whose outputs the deploy role may read
|
|
11
15
|
ArtifactBucketName: { Type: String }
|
|
12
16
|
CloudFormationExecutionRoleArn: { Type: String }
|
|
13
17
|
|
|
18
|
+
Conditions:
|
|
19
|
+
HasConsumerGatewayStack: !Not [!Equals [!Ref ConsumerGatewayStackName, '']]
|
|
20
|
+
|
|
14
21
|
Resources:
|
|
15
22
|
GitHubDeployRole:
|
|
16
23
|
Type: AWS::IAM::Role
|
|
@@ -49,6 +56,13 @@ Resources:
|
|
|
49
56
|
Effect: Allow
|
|
50
57
|
Action: [cloudformation:CreateChangeSet, cloudformation:DescribeChangeSet, cloudformation:ExecuteChangeSet, cloudformation:DeleteChangeSet, cloudformation:DescribeStacks, cloudformation:DescribeStackEvents, cloudformation:GetTemplate, cloudformation:GetTemplateSummary]
|
|
51
58
|
Resource: !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${ApplicationStackName}/*'
|
|
59
|
+
- !If
|
|
60
|
+
- HasConsumerGatewayStack
|
|
61
|
+
- Sid: ReadConsumerGatewayStack
|
|
62
|
+
Effect: Allow
|
|
63
|
+
Action: cloudformation:DescribeStacks
|
|
64
|
+
Resource: !Sub 'arn:${AWS::Partition}:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${ConsumerGatewayStackName}/*'
|
|
65
|
+
- !Ref AWS::NoValue
|
|
52
66
|
- Sid: PassCoreExecutionRole
|
|
53
67
|
Effect: Allow
|
|
54
68
|
Action: iam:PassRole
|
|
@@ -57,4 +71,5 @@ Resources:
|
|
|
57
71
|
|
|
58
72
|
Outputs:
|
|
59
73
|
BootstrapContractVersion: { Value: '2' }
|
|
74
|
+
BootstrapTemplateRevision: { Value: '2.1' }
|
|
60
75
|
GitHubDeployRoleArn: { Value: !GetAtt GitHubDeployRole.Arn }
|
package/dist/bootstrap.d.ts
CHANGED
|
@@ -28,11 +28,13 @@ export type BootstrapConfig = {
|
|
|
28
28
|
ownerId?: string;
|
|
29
29
|
repositoryId?: string;
|
|
30
30
|
environment?: string;
|
|
31
|
+
consumerGatewayStackName?: string;
|
|
31
32
|
};
|
|
32
33
|
};
|
|
33
34
|
export declare function bootstrapTemplatePath(kind: BootstrapKind): Promise<string>;
|
|
34
35
|
export declare function bootstrapTemplate(kind: BootstrapKind): Promise<string>;
|
|
35
36
|
export declare function bootstrapContractVersion(template: string): string;
|
|
37
|
+
export declare function bootstrapTemplateRevision(template: string): string;
|
|
36
38
|
/** Merges a new parameter set with deployed values without silently dropping configuration. */
|
|
37
39
|
export declare function mergeBootstrapParameters(requested: CloudFormationParameterValue[], deployed: CloudFormationParameterValue[]): CloudFormationParameterValue[];
|
|
38
40
|
/** Validates a caller-captured `describe-stacks` result before an upgrade merges it locally. */
|
package/dist/cli.js
CHANGED
|
@@ -857,6 +857,11 @@ function bootstrapContractVersion(template) {
|
|
|
857
857
|
if (!version) throw new Error("Bootstrap template has no BootstrapContractVersion output");
|
|
858
858
|
return version;
|
|
859
859
|
}
|
|
860
|
+
function bootstrapTemplateRevision(template) {
|
|
861
|
+
const revision = template.match(/BootstrapTemplateRevision:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
|
|
862
|
+
if (!revision) throw new Error("Bootstrap template has no BootstrapTemplateRevision output");
|
|
863
|
+
return revision;
|
|
864
|
+
}
|
|
860
865
|
function mergeBootstrapParameters(requested, deployed) {
|
|
861
866
|
const supplied = new Map(requested.map((entry) => [entry.ParameterKey, entry.ParameterValue]));
|
|
862
867
|
const duplicates = requested.map((entry) => entry.ParameterKey);
|
|
@@ -910,7 +915,7 @@ function requiredBootstrapParameters(kind, values) {
|
|
|
910
915
|
];
|
|
911
916
|
const missing = keys.filter((key) => !values[key]);
|
|
912
917
|
if (missing.length) throw new Error(`Missing required bootstrap values: ${missing.join(", ")}`);
|
|
913
|
-
const optional2 = kind === "core" ? ["RuntimeSecretArn", "ArtifactKmsKeyArn"] : [];
|
|
918
|
+
const optional2 = kind === "core" ? ["RuntimeSecretArn", "ArtifactKmsKeyArn"] : ["ConsumerGatewayStackName"];
|
|
914
919
|
return [...keys, ...optional2].filter((key) => values[key] !== void 0).map((ParameterKey) => ({ ParameterKey, ParameterValue: values[ParameterKey] ?? "" }));
|
|
915
920
|
}
|
|
916
921
|
|
|
@@ -1128,6 +1133,7 @@ async function bootstrapHandoff(input) {
|
|
|
1128
1133
|
GitHubOwnerId: input.config.githubOidc?.ownerId,
|
|
1129
1134
|
GitHubRepositoryId: input.config.githubOidc?.repositoryId,
|
|
1130
1135
|
GitHubEnvironment: input.config.githubOidc?.environment,
|
|
1136
|
+
ConsumerGatewayStackName: input.config.githubOidc?.consumerGatewayStackName,
|
|
1131
1137
|
...coreBootstrapOutputs(core)
|
|
1132
1138
|
});
|
|
1133
1139
|
const templatePath = await bootstrapTemplatePath("github-oidc");
|
|
@@ -1136,7 +1142,11 @@ async function bootstrapHandoff(input) {
|
|
|
1136
1142
|
expectedContracts,
|
|
1137
1143
|
templatePath,
|
|
1138
1144
|
parameterPath: "github-oidc-bootstrap.json",
|
|
1139
|
-
expectedOutputs: [
|
|
1145
|
+
expectedOutputs: [
|
|
1146
|
+
"BootstrapContractVersion",
|
|
1147
|
+
"BootstrapTemplateRevision",
|
|
1148
|
+
"GitHubDeployRoleArn"
|
|
1149
|
+
],
|
|
1140
1150
|
requiredCapturedFiles: [coreCapturePath],
|
|
1141
1151
|
reviewCheckpoints: [
|
|
1142
1152
|
"Review the exact immutable GitHub OIDC subject, audience, bucket lambda/* prefix, application stack, and execution role.",
|
|
@@ -1244,9 +1254,14 @@ async function verifyBootstrap(input) {
|
|
|
1244
1254
|
GitHubEnvironment: github?.environment,
|
|
1245
1255
|
ApplicationStackName: coreOutputs.ApplicationStackName,
|
|
1246
1256
|
ArtifactBucketName: coreOutputs.ArtifactBucketName,
|
|
1247
|
-
CloudFormationExecutionRoleArn: executionRole
|
|
1257
|
+
CloudFormationExecutionRoleArn: executionRole,
|
|
1258
|
+
ConsumerGatewayStackName: github?.consumerGatewayStackName ?? ""
|
|
1248
1259
|
}))
|
|
1249
|
-
assertEqual(
|
|
1260
|
+
assertEqual(
|
|
1261
|
+
key === "ConsumerGatewayStackName" ? oidcParameters[key] ?? "" : oidcParameters[key],
|
|
1262
|
+
value2,
|
|
1263
|
+
`OIDC ${key}`
|
|
1264
|
+
);
|
|
1250
1265
|
if (!/^\d+$/.test(github?.ownerId ?? "") || !/^\d+$/.test(github?.repositoryId ?? ""))
|
|
1251
1266
|
throw new Error("GitHub immutable owner and repository IDs must be numeric");
|
|
1252
1267
|
const [owner, repository, ...extra] = (github?.repository ?? "").split("/");
|
|
@@ -1373,7 +1388,8 @@ async function scaffoldBootstrapManifest(input) {
|
|
|
1373
1388
|
repository,
|
|
1374
1389
|
ownerId,
|
|
1375
1390
|
repositoryId,
|
|
1376
|
-
environment
|
|
1391
|
+
environment,
|
|
1392
|
+
...input.consumerGatewayStackName ? { consumerGatewayStackName: input.consumerGatewayStackName } : {}
|
|
1377
1393
|
}
|
|
1378
1394
|
};
|
|
1379
1395
|
}
|
|
@@ -1832,6 +1848,29 @@ async function runDoctor(options, dependencies = actualDependencies) {
|
|
|
1832
1848
|
if (!response.ok) throw new Error(`${url} returned HTTP ${response.status}`);
|
|
1833
1849
|
return `${url} returned HTTP ${response.status}`;
|
|
1834
1850
|
});
|
|
1851
|
+
if (options.githubOidcStackPath) {
|
|
1852
|
+
const stackPath = options.githubOidcStackPath;
|
|
1853
|
+
const template = await bootstrapTemplate("github-oidc");
|
|
1854
|
+
const expectedRevision = bootstrapTemplateRevision(template);
|
|
1855
|
+
await check("Bootstrap template", async () => {
|
|
1856
|
+
const raw = JSON.parse(await readFile4(stackPath, "utf8"));
|
|
1857
|
+
const stack = raw && typeof raw === "object" && "Stacks" in raw ? raw.Stacks?.[0] : raw;
|
|
1858
|
+
if (!stack || typeof stack !== "object")
|
|
1859
|
+
throw new Error("captured stack JSON contains no stack");
|
|
1860
|
+
const actualRevision = (stack.Outputs ?? []).find(({ OutputKey }) => OutputKey === "BootstrapTemplateRevision")?.OutputValue;
|
|
1861
|
+
if (actualRevision !== expectedRevision)
|
|
1862
|
+
throw new Error(
|
|
1863
|
+
`captured bootstrap revision is ${actualRevision ?? "older or missing"}; current package is ${expectedRevision}; rerun the GitHub OIDC bootstrap review before deploying`
|
|
1864
|
+
);
|
|
1865
|
+
return `GitHub OIDC bootstrap revision ${expectedRevision} is current`;
|
|
1866
|
+
});
|
|
1867
|
+
const checkResult = checks.at(-1);
|
|
1868
|
+
if (checkResult && !checkResult.ok) {
|
|
1869
|
+
checkResult.ok = true;
|
|
1870
|
+
checkResult.warning = true;
|
|
1871
|
+
checkResult.detail = `WARNING: ${checkResult.detail}`;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1835
1874
|
return checks;
|
|
1836
1875
|
}
|
|
1837
1876
|
|
|
@@ -1907,6 +1946,10 @@ function bootstrapValues(config, coreOutputs = {}) {
|
|
|
1907
1946
|
GitHubOwnerId: option("--github-owner-id", config.githubOidc?.ownerId),
|
|
1908
1947
|
GitHubRepositoryId: option("--github-repository-id", config.githubOidc?.repositoryId),
|
|
1909
1948
|
GitHubEnvironment: option("--github-environment", config.githubOidc?.environment),
|
|
1949
|
+
ConsumerGatewayStackName: option(
|
|
1950
|
+
"--consumer-gateway-stack",
|
|
1951
|
+
config.githubOidc?.consumerGatewayStackName
|
|
1952
|
+
),
|
|
1910
1953
|
CloudFormationExecutionRoleArn: option(
|
|
1911
1954
|
"--execution-role-arn",
|
|
1912
1955
|
coreOutputs.CloudFormationExecutionRoleArn
|
|
@@ -1968,7 +2011,11 @@ try {
|
|
|
1968
2011
|
const parametersPath = option("--parameters", "aws-dashboard-parameters.json") ?? "aws-dashboard-parameters.json";
|
|
1969
2012
|
const region2 = option("--region", process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION ?? "us-east-1") ?? "us-east-1";
|
|
1970
2013
|
const checks = await runDoctor(
|
|
1971
|
-
{
|
|
2014
|
+
{
|
|
2015
|
+
parametersPath,
|
|
2016
|
+
region: region2,
|
|
2017
|
+
githubOidcStackPath: option("--github-oidc-stack-json")
|
|
2018
|
+
},
|
|
1972
2019
|
{
|
|
1973
2020
|
async execute(command, commandArgs) {
|
|
1974
2021
|
const { execFile: execFile3 } = await import("node:child_process");
|
|
@@ -1983,7 +2030,9 @@ try {
|
|
|
1983
2030
|
}
|
|
1984
2031
|
);
|
|
1985
2032
|
for (const check of checks)
|
|
1986
|
-
console.log(
|
|
2033
|
+
console.log(
|
|
2034
|
+
`${check.warning ? "WARN" : check.ok ? "PASS" : "FAIL"} ${check.name}: ${check.detail}`
|
|
2035
|
+
);
|
|
1987
2036
|
if (checks.some(({ ok }) => !ok)) process.exitCode = 1;
|
|
1988
2037
|
} else if (args[0] === "parameters") {
|
|
1989
2038
|
const output = option("--output", "aws-dashboard-parameters.json") ?? "aws-dashboard-parameters.json";
|
|
@@ -2053,6 +2102,7 @@ try {
|
|
|
2053
2102
|
accountId: option("--account-id"),
|
|
2054
2103
|
ownerId: option("--github-owner-id"),
|
|
2055
2104
|
repositoryId: option("--github-repository-id"),
|
|
2105
|
+
consumerGatewayStackName: option("--consumer-gateway-stack"),
|
|
2056
2106
|
runner
|
|
2057
2107
|
});
|
|
2058
2108
|
await writeFile3(output, `${JSON.stringify(manifest, null, 2)}
|
|
@@ -2171,6 +2221,12 @@ try {
|
|
|
2171
2221
|
JSON.parse(await readFile5(deployedStackPath, "utf8")),
|
|
2172
2222
|
bootstrapContractVersion(await bootstrapTemplate(kind))
|
|
2173
2223
|
);
|
|
2224
|
+
if (kind === "github-oidc" && !(stack.Parameters ?? []).some(
|
|
2225
|
+
({ ParameterKey }) => ParameterKey === "ConsumerGatewayStackName"
|
|
2226
|
+
))
|
|
2227
|
+
console.error(
|
|
2228
|
+
option("--consumer-gateway-stack", config.githubOidc?.consumerGatewayStackName) ? "NOTICE: this GitHub OIDC stack predates optional consumer gateway-stack reads; the generated parameters will add the configured gateway stack. Review and execute the GitHub OIDC UPDATE change set." : "NOTICE: this GitHub OIDC stack predates optional consumer gateway-stack reads. If your workflow verifies a consumer-owned gateway stack, configure githubOidc.consumerGatewayStackName before reviewing the UPDATE change set; otherwise no bootstrap change is needed."
|
|
2229
|
+
);
|
|
2174
2230
|
parameters = mergeBootstrapParameters(supplied, stack.Parameters ?? []);
|
|
2175
2231
|
}
|
|
2176
2232
|
await writeFile3(output, `${JSON.stringify(parameters, null, 2)}
|
package/dist/doctor.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export type DoctorCheck = {
|
|
|
2
2
|
name: string;
|
|
3
3
|
ok: boolean;
|
|
4
4
|
detail: string;
|
|
5
|
+
warning?: boolean;
|
|
5
6
|
};
|
|
6
7
|
export type DoctorDependencies = {
|
|
7
8
|
execute(command: string, args: string[]): Promise<string>;
|
|
@@ -15,4 +16,5 @@ export type DoctorDependencies = {
|
|
|
15
16
|
export declare function runDoctor(options: {
|
|
16
17
|
parametersPath: string;
|
|
17
18
|
region: string;
|
|
19
|
+
githubOidcStackPath?: string;
|
|
18
20
|
}, dependencies?: DoctorDependencies): Promise<DoctorCheck[]>;
|
package/dist/guided.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export type BootstrapInitInput = {
|
|
|
19
19
|
accountId?: string;
|
|
20
20
|
ownerId?: string;
|
|
21
21
|
repositoryId?: string;
|
|
22
|
+
consumerGatewayStackName?: string;
|
|
22
23
|
runner?: CommandRunner;
|
|
23
24
|
};
|
|
24
25
|
/** Creates the non-secret manifest data; callers control where (and whether) it is written. */
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { type BootstrapConfig, type BootstrapKind, bootstrapContractVersion, bootstrapTemplate, bootstrapTemplatePath, type CloudFormationParameterValue, coreBootstrapOutputs, type DeployedBootstrapStack, deployedBootstrapStack, mergeBootstrapParameters, requiredBootstrapParameters, } from './bootstrap.js';
|
|
1
|
+
export { type BootstrapConfig, type BootstrapKind, bootstrapContractVersion, bootstrapTemplate, bootstrapTemplatePath, bootstrapTemplateRevision, type CloudFormationParameterValue, coreBootstrapOutputs, type DeployedBootstrapStack, deployedBootstrapStack, mergeBootstrapParameters, requiredBootstrapParameters, } from './bootstrap.js';
|
|
2
2
|
export { type BootstrapCheckStatus, type BootstrapInitInput, type BootstrapPreflight, type BootstrapPreflightCheck, bootstrapGuide, bootstrapPreflight, scaffoldBootstrapManifest, } from './guided.js';
|
|
3
3
|
export { type BootstrapHandoff, type BootstrapPhase, type BootstrapProvider, type BootstrapVerification, bootstrapHandoff, type CommandRunner, githubOidcProvider, verifyBootstrap, } from './handoff.js';
|
|
4
4
|
export type ReleaseMetadata = {
|
package/dist/index.js
CHANGED
|
@@ -844,6 +844,11 @@ function bootstrapContractVersion(template) {
|
|
|
844
844
|
if (!version) throw new Error("Bootstrap template has no BootstrapContractVersion output");
|
|
845
845
|
return version;
|
|
846
846
|
}
|
|
847
|
+
function bootstrapTemplateRevision(template) {
|
|
848
|
+
const revision = template.match(/BootstrapTemplateRevision:\s*\{\s*Value:\s*'([^']+)'\s*}/)?.[1];
|
|
849
|
+
if (!revision) throw new Error("Bootstrap template has no BootstrapTemplateRevision output");
|
|
850
|
+
return revision;
|
|
851
|
+
}
|
|
847
852
|
function mergeBootstrapParameters(requested, deployed) {
|
|
848
853
|
const supplied = new Map(requested.map((entry) => [entry.ParameterKey, entry.ParameterValue]));
|
|
849
854
|
const duplicates = requested.map((entry) => entry.ParameterKey);
|
|
@@ -897,7 +902,7 @@ function requiredBootstrapParameters(kind, values) {
|
|
|
897
902
|
];
|
|
898
903
|
const missing = keys.filter((key) => !values[key]);
|
|
899
904
|
if (missing.length) throw new Error(`Missing required bootstrap values: ${missing.join(", ")}`);
|
|
900
|
-
const optional2 = kind === "core" ? ["RuntimeSecretArn", "ArtifactKmsKeyArn"] : [];
|
|
905
|
+
const optional2 = kind === "core" ? ["RuntimeSecretArn", "ArtifactKmsKeyArn"] : ["ConsumerGatewayStackName"];
|
|
901
906
|
return [...keys, ...optional2].filter((key) => values[key] !== void 0).map((ParameterKey) => ({ ParameterKey, ParameterValue: values[ParameterKey] ?? "" }));
|
|
902
907
|
}
|
|
903
908
|
|
|
@@ -1115,6 +1120,7 @@ async function bootstrapHandoff(input) {
|
|
|
1115
1120
|
GitHubOwnerId: input.config.githubOidc?.ownerId,
|
|
1116
1121
|
GitHubRepositoryId: input.config.githubOidc?.repositoryId,
|
|
1117
1122
|
GitHubEnvironment: input.config.githubOidc?.environment,
|
|
1123
|
+
ConsumerGatewayStackName: input.config.githubOidc?.consumerGatewayStackName,
|
|
1118
1124
|
...coreBootstrapOutputs(core)
|
|
1119
1125
|
});
|
|
1120
1126
|
const templatePath = await bootstrapTemplatePath("github-oidc");
|
|
@@ -1123,7 +1129,11 @@ async function bootstrapHandoff(input) {
|
|
|
1123
1129
|
expectedContracts,
|
|
1124
1130
|
templatePath,
|
|
1125
1131
|
parameterPath: "github-oidc-bootstrap.json",
|
|
1126
|
-
expectedOutputs: [
|
|
1132
|
+
expectedOutputs: [
|
|
1133
|
+
"BootstrapContractVersion",
|
|
1134
|
+
"BootstrapTemplateRevision",
|
|
1135
|
+
"GitHubDeployRoleArn"
|
|
1136
|
+
],
|
|
1127
1137
|
requiredCapturedFiles: [coreCapturePath],
|
|
1128
1138
|
reviewCheckpoints: [
|
|
1129
1139
|
"Review the exact immutable GitHub OIDC subject, audience, bucket lambda/* prefix, application stack, and execution role.",
|
|
@@ -1231,9 +1241,14 @@ async function verifyBootstrap(input) {
|
|
|
1231
1241
|
GitHubEnvironment: github?.environment,
|
|
1232
1242
|
ApplicationStackName: coreOutputs.ApplicationStackName,
|
|
1233
1243
|
ArtifactBucketName: coreOutputs.ArtifactBucketName,
|
|
1234
|
-
CloudFormationExecutionRoleArn: executionRole
|
|
1244
|
+
CloudFormationExecutionRoleArn: executionRole,
|
|
1245
|
+
ConsumerGatewayStackName: github?.consumerGatewayStackName ?? ""
|
|
1235
1246
|
}))
|
|
1236
|
-
assertEqual(
|
|
1247
|
+
assertEqual(
|
|
1248
|
+
key === "ConsumerGatewayStackName" ? oidcParameters[key] ?? "" : oidcParameters[key],
|
|
1249
|
+
value2,
|
|
1250
|
+
`OIDC ${key}`
|
|
1251
|
+
);
|
|
1237
1252
|
if (!/^\d+$/.test(github?.ownerId ?? "") || !/^\d+$/.test(github?.repositoryId ?? ""))
|
|
1238
1253
|
throw new Error("GitHub immutable owner and repository IDs must be numeric");
|
|
1239
1254
|
const [owner, repository, ...extra] = (github?.repository ?? "").split("/");
|
|
@@ -1360,7 +1375,8 @@ async function scaffoldBootstrapManifest(input) {
|
|
|
1360
1375
|
repository,
|
|
1361
1376
|
ownerId,
|
|
1362
1377
|
repositoryId,
|
|
1363
|
-
environment
|
|
1378
|
+
environment,
|
|
1379
|
+
...input.consumerGatewayStackName ? { consumerGatewayStackName: input.consumerGatewayStackName } : {}
|
|
1364
1380
|
}
|
|
1365
1381
|
};
|
|
1366
1382
|
}
|
|
@@ -1694,6 +1710,7 @@ export {
|
|
|
1694
1710
|
bootstrapPreflight,
|
|
1695
1711
|
bootstrapTemplate,
|
|
1696
1712
|
bootstrapTemplatePath,
|
|
1713
|
+
bootstrapTemplateRevision,
|
|
1697
1714
|
cloudFormationTemplate,
|
|
1698
1715
|
coreBootstrapOutputs,
|
|
1699
1716
|
deployLambda,
|