@pagopa/dx-cli 0.19.1 → 0.19.3
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/dist/adapters/commander/commands/init.js +8 -5
- package/dist/adapters/pagopa-technology/__tests__/authorization.test.js +88 -29
- package/dist/adapters/pagopa-technology/authorization.d.ts +1 -1
- package/dist/adapters/pagopa-technology/authorization.js +34 -14
- package/dist/adapters/plop/generators/environment/actions.js +4 -4
- package/package.json +13 -13
- package/templates/environment/bootstrapper/{{env.name}}/main.tf.hbs +26 -0
|
@@ -45,6 +45,8 @@ const azureAccountSchema = z.object({
|
|
|
45
45
|
});
|
|
46
46
|
const ensureAzLogin = async () => {
|
|
47
47
|
const { stdout } = await tf$ `az account show`;
|
|
48
|
+
// `az account show` reads the cached CLI context, but `az group list`
|
|
49
|
+
// fails when the current session token has expired.
|
|
48
50
|
await tf$ `az group list`;
|
|
49
51
|
const parsed = JSON.parse(stdout);
|
|
50
52
|
const { user } = azureAccountSchema.parse(parsed);
|
|
@@ -79,12 +81,13 @@ const initializeGitRepository = (repository) => {
|
|
|
79
81
|
});
|
|
80
82
|
const pushToOrigin = async () => {
|
|
81
83
|
await git$ `git init`;
|
|
82
|
-
await git$ `git add README.md`;
|
|
83
|
-
await git$ `git commit --no-gpg-sign -m "Create README.md"`;
|
|
84
|
-
await git$ `git branch -M main`;
|
|
85
84
|
await git$ `git remote add origin ${repository.origin}`;
|
|
86
|
-
await git$ `git
|
|
87
|
-
await git$ `git
|
|
85
|
+
await git$ `git fetch origin main`;
|
|
86
|
+
await git$ `git checkout -b ${branchName}`;
|
|
87
|
+
// Terraform creates `main` with an initial README commit.
|
|
88
|
+
// Reset to `origin/main` so this branch is based on the remote default branch,
|
|
89
|
+
// while keeping the scaffolded local files in the working tree for a clean PR diff.
|
|
90
|
+
await git$ `git reset origin/main`;
|
|
88
91
|
await git$ `git add .`;
|
|
89
92
|
await git$ `git commit --no-gpg-sign -m "Scaffold workspace"`;
|
|
90
93
|
await git$ `git push -u origin ${branchName}`;
|
|
@@ -19,17 +19,14 @@ const makeSampleInput = () => requestAuthorizationInputSchema.parse({
|
|
|
19
19
|
repoName: "test-repo",
|
|
20
20
|
subscriptionName: "test-subscription",
|
|
21
21
|
});
|
|
22
|
+
const FILE_PATH = "src/azure-subscriptions/subscriptions/test-subscription/terraform.tfvars.json";
|
|
22
23
|
// eslint-disable-next-line max-lines-per-function
|
|
23
24
|
describe("PagoPA AuthorizationService", () => {
|
|
24
25
|
describe("happy path", () => {
|
|
25
26
|
it("should create a pull request when all steps succeed", async () => {
|
|
26
27
|
const { authorizationService, gitHubService } = makeEnv();
|
|
27
28
|
const input = makeSampleInput();
|
|
28
|
-
const originalContent =
|
|
29
|
-
directory_readers = {
|
|
30
|
-
service_principals_name = []
|
|
31
|
-
}
|
|
32
|
-
`.trim();
|
|
29
|
+
const originalContent = JSON.stringify({ directory_readers: { service_principals_name: [] } }, null, 2);
|
|
33
30
|
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
34
31
|
gitHubService.getFileContent.mockResolvedValue({
|
|
35
32
|
content: originalContent,
|
|
@@ -50,7 +47,7 @@ directory_readers = {
|
|
|
50
47
|
});
|
|
51
48
|
expect(gitHubService.getFileContent).toHaveBeenCalledWith({
|
|
52
49
|
owner: "pagopa",
|
|
53
|
-
path:
|
|
50
|
+
path: FILE_PATH,
|
|
54
51
|
ref: "feats/add-test-repo-test-subscription-bootstrap-identity",
|
|
55
52
|
repo: "eng-azure-authorization",
|
|
56
53
|
});
|
|
@@ -58,7 +55,7 @@ directory_readers = {
|
|
|
58
55
|
branch: "feats/add-test-repo-test-subscription-bootstrap-identity",
|
|
59
56
|
message: "Add directory reader for test-subscription",
|
|
60
57
|
owner: "pagopa",
|
|
61
|
-
path:
|
|
58
|
+
path: FILE_PATH,
|
|
62
59
|
repo: "eng-azure-authorization",
|
|
63
60
|
sha: "original-sha-123",
|
|
64
61
|
}));
|
|
@@ -71,30 +68,88 @@ directory_readers = {
|
|
|
71
68
|
title: "Add directory reader for test-subscription",
|
|
72
69
|
});
|
|
73
70
|
});
|
|
71
|
+
it("should preserve existing fields in the JSON file", async () => {
|
|
72
|
+
const { authorizationService, gitHubService } = makeEnv();
|
|
73
|
+
const input = makeSampleInput();
|
|
74
|
+
const originalContent = JSON.stringify({
|
|
75
|
+
directory_readers: {
|
|
76
|
+
service_principals_name: ["existing-identity"],
|
|
77
|
+
some_other_field: "keep-me",
|
|
78
|
+
},
|
|
79
|
+
entra_groups: {
|
|
80
|
+
readers: ["reader-group"],
|
|
81
|
+
},
|
|
82
|
+
other_top_level: true,
|
|
83
|
+
}, null, 2);
|
|
84
|
+
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
85
|
+
gitHubService.getFileContent.mockResolvedValue({
|
|
86
|
+
content: originalContent,
|
|
87
|
+
sha: "sha-789",
|
|
88
|
+
});
|
|
89
|
+
gitHubService.updateFile.mockResolvedValue(undefined);
|
|
90
|
+
gitHubService.createPullRequest.mockResolvedValue(new PullRequest("https://github.com/pagopa/eng-azure-authorization/pull/44"));
|
|
91
|
+
const result = await authorizationService.requestAuthorization(input);
|
|
92
|
+
expect(result.isOk()).toBe(true);
|
|
93
|
+
const updateCall = gitHubService.updateFile.mock.calls[0][0];
|
|
94
|
+
const updatedParsed = JSON.parse(updateCall.content);
|
|
95
|
+
expect(updatedParsed).toStrictEqual({
|
|
96
|
+
directory_readers: {
|
|
97
|
+
service_principals_name: [
|
|
98
|
+
"existing-identity",
|
|
99
|
+
"test-bootstrap-identity-id",
|
|
100
|
+
],
|
|
101
|
+
some_other_field: "keep-me",
|
|
102
|
+
},
|
|
103
|
+
entra_groups: {
|
|
104
|
+
readers: ["reader-group"],
|
|
105
|
+
},
|
|
106
|
+
other_top_level: true,
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
it("should append identity to an existing non-empty list", async () => {
|
|
110
|
+
const { authorizationService, gitHubService } = makeEnv();
|
|
111
|
+
const input = makeSampleInput();
|
|
112
|
+
const originalContent = JSON.stringify({
|
|
113
|
+
directory_readers: {
|
|
114
|
+
service_principals_name: ["existing-identity"],
|
|
115
|
+
},
|
|
116
|
+
}, null, 2);
|
|
117
|
+
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
118
|
+
gitHubService.getFileContent.mockResolvedValue({
|
|
119
|
+
content: originalContent,
|
|
120
|
+
sha: "sha-456",
|
|
121
|
+
});
|
|
122
|
+
gitHubService.updateFile.mockResolvedValue(undefined);
|
|
123
|
+
gitHubService.createPullRequest.mockResolvedValue(new PullRequest("https://github.com/pagopa/eng-azure-authorization/pull/43"));
|
|
124
|
+
const result = await authorizationService.requestAuthorization(input);
|
|
125
|
+
expect(result.isOk()).toBe(true);
|
|
126
|
+
const updateCall = gitHubService.updateFile.mock.calls[0][0];
|
|
127
|
+
const updatedParsed = JSON.parse(updateCall.content);
|
|
128
|
+
expect(updatedParsed.directory_readers.service_principals_name).toContain("test-bootstrap-identity-id");
|
|
129
|
+
expect(updatedParsed.directory_readers.service_principals_name).toContain("existing-identity");
|
|
130
|
+
});
|
|
74
131
|
});
|
|
75
132
|
describe("error handling", () => {
|
|
76
133
|
it("should return error when file is not found", async () => {
|
|
77
134
|
const { authorizationService, gitHubService } = makeEnv();
|
|
78
135
|
const input = makeSampleInput();
|
|
79
136
|
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
80
|
-
gitHubService.getFileContent.mockRejectedValue(new FileNotFoundError(
|
|
137
|
+
gitHubService.getFileContent.mockRejectedValue(new FileNotFoundError(FILE_PATH));
|
|
81
138
|
const result = await authorizationService.requestAuthorization(input);
|
|
82
139
|
expect(result.isErr()).toBe(true);
|
|
83
140
|
const error = result._unsafeUnwrapErr();
|
|
84
141
|
expect(error.message).toContain("Unable to get");
|
|
85
|
-
expect(error.message).toContain("
|
|
142
|
+
expect(error.message).toContain("terraform.tfvars.json");
|
|
86
143
|
expect(gitHubService.updateFile).not.toHaveBeenCalled();
|
|
87
144
|
});
|
|
88
145
|
it("should return error when identity already exists", async () => {
|
|
89
146
|
const { authorizationService, gitHubService } = makeEnv();
|
|
90
147
|
const input = makeSampleInput();
|
|
91
|
-
const content =
|
|
92
|
-
directory_readers
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
}
|
|
97
|
-
`.trim();
|
|
148
|
+
const content = JSON.stringify({
|
|
149
|
+
directory_readers: {
|
|
150
|
+
service_principals_name: ["test-bootstrap-identity-id"],
|
|
151
|
+
},
|
|
152
|
+
}, null, 2);
|
|
98
153
|
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
99
154
|
gitHubService.getFileContent.mockResolvedValue({
|
|
100
155
|
content,
|
|
@@ -105,13 +160,25 @@ directory_readers = {
|
|
|
105
160
|
expect(result._unsafeUnwrapErr()).toBeInstanceOf(IdentityAlreadyExistsError);
|
|
106
161
|
expect(gitHubService.updateFile).not.toHaveBeenCalled();
|
|
107
162
|
});
|
|
108
|
-
it("should return error when
|
|
163
|
+
it("should return error when file content is not valid JSON", async () => {
|
|
164
|
+
const { authorizationService, gitHubService } = makeEnv();
|
|
165
|
+
const input = makeSampleInput();
|
|
166
|
+
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
167
|
+
gitHubService.getFileContent.mockResolvedValue({
|
|
168
|
+
content: "not valid json {{",
|
|
169
|
+
sha: "sha-123",
|
|
170
|
+
});
|
|
171
|
+
const result = await authorizationService.requestAuthorization(input);
|
|
172
|
+
expect(result.isErr()).toBe(true);
|
|
173
|
+
expect(result._unsafeUnwrapErr()).toBeInstanceOf(InvalidAuthorizationFileFormatError);
|
|
174
|
+
expect(gitHubService.updateFile).not.toHaveBeenCalled();
|
|
175
|
+
});
|
|
176
|
+
it("should return error when JSON is missing expected keys", async () => {
|
|
109
177
|
const { authorizationService, gitHubService } = makeEnv();
|
|
110
178
|
const input = makeSampleInput();
|
|
111
|
-
const invalidContent = "invalid content without directory_readers";
|
|
112
179
|
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
113
180
|
gitHubService.getFileContent.mockResolvedValue({
|
|
114
|
-
content:
|
|
181
|
+
content: JSON.stringify({ unexpected_key: {} }),
|
|
115
182
|
sha: "sha-123",
|
|
116
183
|
});
|
|
117
184
|
const result = await authorizationService.requestAuthorization(input);
|
|
@@ -132,11 +199,7 @@ directory_readers = {
|
|
|
132
199
|
it("should return error when file update fails", async () => {
|
|
133
200
|
const { authorizationService, gitHubService } = makeEnv();
|
|
134
201
|
const input = makeSampleInput();
|
|
135
|
-
const content =
|
|
136
|
-
directory_readers = {
|
|
137
|
-
service_principals_name = []
|
|
138
|
-
}
|
|
139
|
-
`.trim();
|
|
202
|
+
const content = JSON.stringify({ directory_readers: { service_principals_name: [] } }, null, 2);
|
|
140
203
|
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
141
204
|
gitHubService.getFileContent.mockResolvedValue({
|
|
142
205
|
content,
|
|
@@ -151,11 +214,7 @@ directory_readers = {
|
|
|
151
214
|
it("should return error when PR creation fails", async () => {
|
|
152
215
|
const { authorizationService, gitHubService } = makeEnv();
|
|
153
216
|
const input = makeSampleInput();
|
|
154
|
-
const content =
|
|
155
|
-
directory_readers = {
|
|
156
|
-
service_principals_name = []
|
|
157
|
-
}
|
|
158
|
-
`.trim();
|
|
217
|
+
const content = JSON.stringify({ directory_readers: { service_principals_name: [] } }, null, 2);
|
|
159
218
|
gitHubService.createBranch.mockResolvedValue(undefined);
|
|
160
219
|
gitHubService.getFileContent.mockResolvedValue({
|
|
161
220
|
content,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Implements the AuthorizationService interface for the PagoPA Azure
|
|
5
5
|
* authorization workflow. Encapsulates all platform-specific details:
|
|
6
|
-
* the target GitHub repository, file paths, branch naming,
|
|
6
|
+
* the target GitHub repository, file paths, branch naming, JSON file
|
|
7
7
|
* parsing, and pull request creation.
|
|
8
8
|
*/
|
|
9
9
|
import { AuthorizationService } from "../../domain/authorization.js";
|
|
@@ -3,29 +3,49 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Implements the AuthorizationService interface for the PagoPA Azure
|
|
5
5
|
* authorization workflow. Encapsulates all platform-specific details:
|
|
6
|
-
* the target GitHub repository, file paths, branch naming,
|
|
6
|
+
* the target GitHub repository, file paths, branch naming, JSON file
|
|
7
7
|
* parsing, and pull request creation.
|
|
8
8
|
*/
|
|
9
9
|
import { getLogger } from "@logtape/logtape";
|
|
10
10
|
import { err, errAsync, ok, okAsync, ResultAsync } from "neverthrow";
|
|
11
|
+
import { z } from "zod";
|
|
11
12
|
import { AuthorizationError, AuthorizationResult, IdentityAlreadyExistsError, InvalidAuthorizationFileFormatError, } from "../../domain/authorization.js";
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
const authorizationFileSchema = z
|
|
14
|
+
.object({
|
|
15
|
+
directory_readers: z
|
|
16
|
+
.object({
|
|
17
|
+
service_principals_name: z.array(z.string()),
|
|
18
|
+
})
|
|
19
|
+
.loose(),
|
|
20
|
+
})
|
|
21
|
+
.loose();
|
|
14
22
|
const addIdentity = (content, identityId) => {
|
|
15
|
-
|
|
16
|
-
|
|
23
|
+
let parsed;
|
|
24
|
+
try {
|
|
25
|
+
parsed = JSON.parse(content);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return err(new InvalidAuthorizationFileFormatError("File content is not valid JSON"));
|
|
29
|
+
}
|
|
30
|
+
const result = authorizationFileSchema.safeParse(parsed);
|
|
31
|
+
if (!result.success) {
|
|
17
32
|
return err(new InvalidAuthorizationFileFormatError("Could not find directory_readers.service_principals_name list"));
|
|
18
33
|
}
|
|
19
|
-
const
|
|
20
|
-
if (
|
|
34
|
+
const jsonContent = result.data;
|
|
35
|
+
if (jsonContent.directory_readers.service_principals_name.includes(identityId)) {
|
|
21
36
|
return err(new IdentityAlreadyExistsError(identityId));
|
|
22
37
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
const updated = {
|
|
39
|
+
...jsonContent,
|
|
40
|
+
directory_readers: {
|
|
41
|
+
...jsonContent.directory_readers,
|
|
42
|
+
service_principals_name: [
|
|
43
|
+
...jsonContent.directory_readers.service_principals_name,
|
|
44
|
+
identityId,
|
|
45
|
+
],
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
return ok(JSON.stringify(updated, null, 2));
|
|
29
49
|
};
|
|
30
50
|
const REPO_OWNER = "pagopa";
|
|
31
51
|
const REPO_NAME = "eng-azure-authorization";
|
|
@@ -34,7 +54,7 @@ export const makeAuthorizationService = (gitHubService) => ({
|
|
|
34
54
|
requestAuthorization(input) {
|
|
35
55
|
const logger = getLogger(["dx-cli", "pagopa-authorization"]);
|
|
36
56
|
const { bootstrapIdentityId, repoName, subscriptionName } = input;
|
|
37
|
-
const filePath = `src/azure-subscriptions/subscriptions/${subscriptionName}/terraform.tfvars`;
|
|
57
|
+
const filePath = `src/azure-subscriptions/subscriptions/${subscriptionName}/terraform.tfvars.json`;
|
|
38
58
|
const branchName = `feats/add-${repoName}-${subscriptionName}-bootstrap-identity`;
|
|
39
59
|
return (
|
|
40
60
|
// Step 1: Create branch first to avoid race condition with main branch updates
|
|
@@ -2,14 +2,14 @@ import { getLogger } from "@logtape/logtape";
|
|
|
2
2
|
import * as path from "node:path";
|
|
3
3
|
import { formatTerraformCode } from "../../../terraform/fmt.js";
|
|
4
4
|
import { payloadSchema } from "./prompts.js";
|
|
5
|
-
const addModule = (env, templatesPath) => {
|
|
5
|
+
const addModule = (env, templatesPath, init = false) => {
|
|
6
6
|
const cloudAccountsByCsp = Object.groupBy(env.cloudAccounts, (account) => account.csp);
|
|
7
7
|
const includesProdIO = env.cloudAccounts.some((account) => account.displayName === "PROD-IO");
|
|
8
8
|
const cwd = process.cwd();
|
|
9
9
|
return (name, terraformBackendKey) => [
|
|
10
10
|
{
|
|
11
11
|
base: templatesPath,
|
|
12
|
-
data: { cloudAccountsByCsp, includesProdIO },
|
|
12
|
+
data: { cloudAccountsByCsp, includesProdIO, init },
|
|
13
13
|
destination: path.join(cwd, "infra"),
|
|
14
14
|
force: true,
|
|
15
15
|
templateFiles: path.join(templatesPath, name),
|
|
@@ -19,7 +19,7 @@ const addModule = (env, templatesPath) => {
|
|
|
19
19
|
},
|
|
20
20
|
{
|
|
21
21
|
base: path.join(templatesPath, "shared"),
|
|
22
|
-
data: { cloudAccountsByCsp, terraformBackendKey },
|
|
22
|
+
data: { cloudAccountsByCsp, init, terraformBackendKey },
|
|
23
23
|
destination: path.join(cwd, "infra", name, "{{env.name}}"),
|
|
24
24
|
force: true,
|
|
25
25
|
templateFiles: path.join(templatesPath, "shared"),
|
|
@@ -34,7 +34,7 @@ export default function getActions(templatesPath) {
|
|
|
34
34
|
const logger = getLogger(["gen", "env"]);
|
|
35
35
|
logger.debug("payload {payload}", { payload });
|
|
36
36
|
const { env, github, init } = payloadSchema.parse(payload);
|
|
37
|
-
const addEnvironmentModule = addModule(env, templatesPath);
|
|
37
|
+
const addEnvironmentModule = addModule(env, templatesPath, !!init);
|
|
38
38
|
const actions = [
|
|
39
39
|
{
|
|
40
40
|
type: "getTerraformBackend",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagopa/dx-cli",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A CLI useful to manage DX tools.",
|
|
6
6
|
"repository": {
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
"@azure/arm-resources": "^7.0.0",
|
|
29
29
|
"@azure/arm-resources-subscriptions": "^2.1.0",
|
|
30
30
|
"@azure/arm-storage": "^19.1.0",
|
|
31
|
-
"@azure/identity": "^4.13.
|
|
32
|
-
"@azure/keyvault-secrets": "^4.
|
|
33
|
-
"@azure/storage-blob": "^12.
|
|
31
|
+
"@azure/identity": "^4.13.1",
|
|
32
|
+
"@azure/keyvault-secrets": "^4.11.1",
|
|
33
|
+
"@azure/storage-blob": "^12.31.0",
|
|
34
34
|
"@logtape/logtape": "^1.3.7",
|
|
35
35
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
|
36
36
|
"chalk": "^5.6.2",
|
|
37
37
|
"commander": "^14.0.3",
|
|
38
|
-
"core-js": "^3.
|
|
38
|
+
"core-js": "^3.49.0",
|
|
39
39
|
"execa": "^9.6.1",
|
|
40
40
|
"glob": "^11.1.0",
|
|
41
41
|
"inquirer": "^9.3.8",
|
|
@@ -45,24 +45,24 @@
|
|
|
45
45
|
"ora": "^9.3.0",
|
|
46
46
|
"replace-in-file": "^8.4.0",
|
|
47
47
|
"semver": "^7.7.4",
|
|
48
|
-
"yaml": "^2.8.
|
|
48
|
+
"yaml": "^2.8.3",
|
|
49
49
|
"zod": "^4.3.6",
|
|
50
|
-
"@pagopa/dx-savemoney": "^0.2.
|
|
50
|
+
"@pagopa/dx-savemoney": "^0.2.4"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@tsconfig/node24": "24.0.4",
|
|
54
54
|
"@types/inquirer": "^9.0.9",
|
|
55
|
-
"@types/node": "^22.19.
|
|
55
|
+
"@types/node": "^22.19.17",
|
|
56
56
|
"@types/semver": "^7.7.1",
|
|
57
57
|
"@vitest/coverage-v8": "^3.2.4",
|
|
58
|
-
"eslint": "^10.
|
|
59
|
-
"memfs": "^4.
|
|
58
|
+
"eslint": "^10.2.0",
|
|
59
|
+
"memfs": "^4.57.1",
|
|
60
60
|
"plop": "^4.0.5",
|
|
61
|
-
"prettier": "3.8.
|
|
61
|
+
"prettier": "3.8.3",
|
|
62
62
|
"typescript": "~5.9.3",
|
|
63
63
|
"vitest": "^3.2.4",
|
|
64
|
-
"vitest-mock-extended": "^3.1.
|
|
65
|
-
"@pagopa/eslint-config": "^6.0.
|
|
64
|
+
"vitest-mock-extended": "^3.1.1",
|
|
65
|
+
"@pagopa/eslint-config": "^6.0.3"
|
|
66
66
|
},
|
|
67
67
|
"engines": {
|
|
68
68
|
"node": ">=22.0.0"
|
|
@@ -120,6 +120,32 @@ module "azure-{{displayName}}_bootstrap" {
|
|
|
120
120
|
|
|
121
121
|
tags = local.bootstrapper_tags
|
|
122
122
|
}
|
|
123
|
+
|
|
124
|
+
{{#if @root.init}}
|
|
125
|
+
resource "azurerm_role_assignment" "infra_cd_user_access_admin_common_rg_{{displayName}}" {
|
|
126
|
+
provider = azurerm.{{displayName}}
|
|
127
|
+
|
|
128
|
+
scope = module.azure-{{displayName}}_core_values.common_resource_group_id
|
|
129
|
+
role_definition_name = "User Access Administrator"
|
|
130
|
+
principal_id = module.azure-{{displayName}}_bootstrap.identities.infra.cd.principal_id
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
resource "azurerm_role_assignment" "infra_cd_kv_secrets_officer_common_{{displayName}}" {
|
|
134
|
+
provider = azurerm.{{displayName}}
|
|
135
|
+
|
|
136
|
+
scope = module.azure-{{displayName}}_core_values.common_key_vault.id
|
|
137
|
+
role_definition_name = "Key Vault Secrets Officer"
|
|
138
|
+
principal_id = module.azure-{{displayName}}_bootstrap.identities.infra.cd.principal_id
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
resource "azurerm_role_assignment" "infra_ci_kv_secrets_user_common_{{displayName}}" {
|
|
142
|
+
provider = azurerm.{{displayName}}
|
|
143
|
+
|
|
144
|
+
scope = module.azure-{{displayName}}_core_values.common_key_vault.id
|
|
145
|
+
role_definition_name = "Key Vault Secrets User"
|
|
146
|
+
principal_id = module.azure-{{displayName}}_bootstrap.identities.infra.ci.principal_id
|
|
147
|
+
}
|
|
148
|
+
{{/if}}
|
|
123
149
|
{{/if}}
|
|
124
150
|
{{/each}}
|
|
125
151
|
|