@pagopa/dx-cli 0.22.4 → 0.23.1
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 +18 -0
- package/dist/adapters/commander/commands/add.d.ts +2 -6
- package/dist/adapters/commander/commands/add.js +4 -8
- package/dist/adapters/commander/commands/init.d.ts +2 -6
- package/dist/adapters/commander/commands/init.js +6 -5
- package/dist/adapters/commander/commands/savemoney.d.ts +11 -0
- package/dist/adapters/commander/commands/savemoney.js +30 -5
- package/dist/adapters/commander/commands/spec.d.ts +10 -0
- package/dist/adapters/commander/commands/spec.js +13 -0
- package/dist/adapters/commander/index.js +6 -2
- package/dist/adapters/commander/spec.d.ts +16 -0
- package/dist/adapters/commander/spec.js +54 -0
- package/dist/adapters/plop/generators/environment/actions.js +3 -3
- package/dist/adapters/plop/index.js +3 -5
- package/dist/adapters/plop/templates-path.d.ts +5 -0
- package/dist/adapters/plop/templates-path.js +6 -0
- package/dist/domain/dependencies.d.ts +15 -2
- package/dist/domain/spec.d.ts +50 -0
- package/dist/domain/spec.js +8 -0
- package/dist/index.js +15 -12
- package/package.json +5 -5
- package/templates/monorepo/nx.json +0 -1
- package/dist/adapters/azure/__tests__/cloud-account-repository.test.d.ts +0 -1
- package/dist/adapters/azure/__tests__/cloud-account-repository.test.js +0 -95
- package/dist/adapters/azure/__tests__/cloud-account-service.test.d.ts +0 -1
- package/dist/adapters/azure/__tests__/cloud-account-service.test.js +0 -378
- package/dist/adapters/codemods/__tests__/registry.test.d.ts +0 -1
- package/dist/adapters/codemods/__tests__/registry.test.js +0 -56
- package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.d.ts +0 -1
- package/dist/adapters/codemods/__tests__/use-azure-appsvc.test.js +0 -77
- package/dist/adapters/codemods/__tests__/use-pnpm.test.d.ts +0 -1
- package/dist/adapters/codemods/__tests__/use-pnpm.test.js +0 -148
- package/dist/adapters/commander/__tests__/env.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/env.test.js +0 -45
- package/dist/adapters/commander/__tests__/error-reporting.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/error-reporting.test.js +0 -63
- package/dist/adapters/commander/__tests__/exit-with-error.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/exit-with-error.test.js +0 -92
- package/dist/adapters/commander/__tests__/global-options.test.d.ts +0 -1
- package/dist/adapters/commander/__tests__/global-options.test.js +0 -33
- package/dist/adapters/commander/commands/__tests__/add.test.d.ts +0 -4
- package/dist/adapters/commander/commands/__tests__/add.test.js +0 -167
- package/dist/adapters/commander/commands/__tests__/init.test.d.ts +0 -4
- package/dist/adapters/commander/commands/__tests__/init.test.js +0 -48
- package/dist/adapters/commander/commands/__tests__/preconditions.test.d.ts +0 -1
- package/dist/adapters/commander/commands/__tests__/preconditions.test.js +0 -32
- package/dist/adapters/commander/presenters/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/commander/presenters/__tests__/index.test.js +0 -23
- package/dist/adapters/commander/presenters/__tests__/json.test.d.ts +0 -1
- package/dist/adapters/commander/presenters/__tests__/json.test.js +0 -108
- package/dist/adapters/commander/presenters/__tests__/text.test.d.ts +0 -1
- package/dist/adapters/commander/presenters/__tests__/text.test.js +0 -60
- package/dist/adapters/github/__tests__/github-repo.spec.d.ts +0 -1
- package/dist/adapters/github/__tests__/github-repo.spec.js +0 -67
- package/dist/adapters/node/__tests__/data.d.ts +0 -18
- package/dist/adapters/node/__tests__/data.js +0 -22
- package/dist/adapters/node/__tests__/package-json.test.d.ts +0 -1
- package/dist/adapters/node/__tests__/package-json.test.js +0 -86
- package/dist/adapters/node/__tests__/repository.test.d.ts +0 -1
- package/dist/adapters/node/__tests__/repository.test.js +0 -77
- package/dist/adapters/node/fs/__tests__/file-reader.test.d.ts +0 -1
- package/dist/adapters/node/fs/__tests__/file-reader.test.js +0 -80
- package/dist/adapters/node/json/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/node/json/__tests__/index.test.js +0 -14
- package/dist/adapters/octokit/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/octokit/__tests__/index.test.js +0 -414
- package/dist/adapters/pagopa-technology/__tests__/authorization.test.d.ts +0 -4
- package/dist/adapters/pagopa-technology/__tests__/authorization.test.js +0 -548
- package/dist/adapters/plop/__tests__/run-actions.test.d.ts +0 -1
- package/dist/adapters/plop/__tests__/run-actions.test.js +0 -68
- package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.d.ts +0 -1
- package/dist/adapters/plop/actions/__tests__/init-cloud-accounts.test.js +0 -171
- package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.d.ts +0 -1
- package/dist/adapters/plop/actions/__tests__/provision-terraform-backend.test.js +0 -134
- package/dist/adapters/plop/generators/environment/__tests__/actions.test.d.ts +0 -2
- package/dist/adapters/plop/generators/environment/__tests__/actions.test.js +0 -92
- package/dist/adapters/plop/generators/environment/__tests__/prompts.test.d.ts +0 -1
- package/dist/adapters/plop/generators/environment/__tests__/prompts.test.js +0 -182
- package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.d.ts +0 -1
- package/dist/adapters/plop/helpers/__tests__/resource-prefix.test.js +0 -113
- package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.d.ts +0 -1
- package/dist/adapters/plop/helpers/__tests__/terraform-state-key.test.js +0 -35
- package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.d.ts +0 -1
- package/dist/adapters/plop/helpers/__tests__/validate-prompt.test.js +0 -60
- package/dist/adapters/yaml/__tests__/index.test.d.ts +0 -1
- package/dist/adapters/yaml/__tests__/index.test.js +0 -53
- package/dist/domain/__tests__/data.d.ts +0 -19
- package/dist/domain/__tests__/data.js +0 -28
- package/dist/domain/__tests__/environment.test.d.ts +0 -1
- package/dist/domain/__tests__/environment.test.js +0 -332
- package/dist/domain/__tests__/info.test.d.ts +0 -1
- package/dist/domain/__tests__/info.test.js +0 -77
- package/dist/domain/__tests__/package-json.test.d.ts +0 -1
- package/dist/domain/__tests__/package-json.test.js +0 -39
- package/dist/domain/__tests__/repository.test.d.ts +0 -1
- package/dist/domain/__tests__/repository.test.js +0 -111
- package/dist/domain/__tests__/workspace.test.d.ts +0 -1
- package/dist/domain/__tests__/workspace.test.js +0 -57
- package/dist/use-cases/__tests__/apply-codemod.test.d.ts +0 -1
- package/dist/use-cases/__tests__/apply-codemod.test.js +0 -71
- package/dist/use-cases/__tests__/list-codemods.test.d.ts +0 -1
- package/dist/use-cases/__tests__/list-codemods.test.js +0 -37
- package/dist/use-cases/__tests__/request-authorization.test.d.ts +0 -4
- package/dist/use-cases/__tests__/request-authorization.test.js +0 -43
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it, vi } from "vitest";
|
|
2
|
-
import { AzureSubscriptionRepository } from "../cloud-account-repository.js";
|
|
3
|
-
const createMockSubscription = (overrides = {}) => ({
|
|
4
|
-
displayName: "Test Subscription",
|
|
5
|
-
state: "Enabled",
|
|
6
|
-
subscriptionId: "00000000-0000-0000-0000-000000000001",
|
|
7
|
-
...overrides,
|
|
8
|
-
});
|
|
9
|
-
const createMockSubscriptionClient = (subscriptions) => {
|
|
10
|
-
const listIterator = async function* () {
|
|
11
|
-
for (const sub of subscriptions) {
|
|
12
|
-
yield sub;
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
return {
|
|
16
|
-
subscriptions: {
|
|
17
|
-
list: listIterator,
|
|
18
|
-
},
|
|
19
|
-
};
|
|
20
|
-
};
|
|
21
|
-
vi.mock("@azure/arm-resources-subscriptions", () => ({
|
|
22
|
-
SubscriptionClient: vi.fn(),
|
|
23
|
-
}));
|
|
24
|
-
vi.mock("@azure/identity", () => ({
|
|
25
|
-
DefaultAzureCredential: vi.fn(),
|
|
26
|
-
}));
|
|
27
|
-
import { SubscriptionClient } from "@azure/arm-resources-subscriptions";
|
|
28
|
-
import { DefaultAzureCredential } from "@azure/identity";
|
|
29
|
-
const MockedSubscriptionClient = SubscriptionClient;
|
|
30
|
-
describe("AzureSubscriptionRepository", () => {
|
|
31
|
-
it("should return a list of enabled subscriptions", async () => {
|
|
32
|
-
const subscriptions = [
|
|
33
|
-
createMockSubscription({
|
|
34
|
-
displayName: "Sub 1",
|
|
35
|
-
subscriptionId: "sub-1",
|
|
36
|
-
}),
|
|
37
|
-
createMockSubscription({
|
|
38
|
-
displayName: "Sub 2",
|
|
39
|
-
subscriptionId: "sub-2",
|
|
40
|
-
}),
|
|
41
|
-
];
|
|
42
|
-
MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient(subscriptions));
|
|
43
|
-
const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
|
|
44
|
-
const result = await repository.list();
|
|
45
|
-
expect(result).toHaveLength(2);
|
|
46
|
-
expect(result[0]).toMatchObject({
|
|
47
|
-
displayName: "Sub 1",
|
|
48
|
-
id: "sub-1",
|
|
49
|
-
});
|
|
50
|
-
expect(result[1]).toMatchObject({
|
|
51
|
-
displayName: "Sub 2",
|
|
52
|
-
id: "sub-2",
|
|
53
|
-
});
|
|
54
|
-
});
|
|
55
|
-
it("should filter out disabled subscriptions", async () => {
|
|
56
|
-
const subscriptions = [
|
|
57
|
-
createMockSubscription({
|
|
58
|
-
displayName: "Enabled Sub",
|
|
59
|
-
state: "Enabled",
|
|
60
|
-
subscriptionId: "enabled-sub",
|
|
61
|
-
}),
|
|
62
|
-
createMockSubscription({
|
|
63
|
-
displayName: "Disabled Sub",
|
|
64
|
-
state: "Disabled",
|
|
65
|
-
subscriptionId: "disabled-sub",
|
|
66
|
-
}),
|
|
67
|
-
];
|
|
68
|
-
MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient(subscriptions));
|
|
69
|
-
const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
|
|
70
|
-
const result = await repository.list();
|
|
71
|
-
expect(result).toHaveLength(1);
|
|
72
|
-
expect(result[0]).toMatchObject({
|
|
73
|
-
displayName: "Enabled Sub",
|
|
74
|
-
id: "enabled-sub",
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
it("should return an empty array when no subscriptions exist", async () => {
|
|
78
|
-
MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient([]));
|
|
79
|
-
const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
|
|
80
|
-
const result = await repository.list();
|
|
81
|
-
expect(result).toEqual([]);
|
|
82
|
-
});
|
|
83
|
-
it("should filter out subscriptions with other states", async () => {
|
|
84
|
-
const subscriptions = [
|
|
85
|
-
createMockSubscription({ state: "Enabled" }),
|
|
86
|
-
createMockSubscription({ state: "Warned" }),
|
|
87
|
-
createMockSubscription({ state: "PastDue" }),
|
|
88
|
-
createMockSubscription({ state: "Deleted" }),
|
|
89
|
-
];
|
|
90
|
-
MockedSubscriptionClient.mockImplementation(() => createMockSubscriptionClient(subscriptions));
|
|
91
|
-
const repository = new AzureSubscriptionRepository(new DefaultAzureCredential());
|
|
92
|
-
const result = await repository.list();
|
|
93
|
-
expect(result).toHaveLength(1);
|
|
94
|
-
});
|
|
95
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,378 +0,0 @@
|
|
|
1
|
-
import { DefaultAzureCredential } from "@azure/identity";
|
|
2
|
-
import { test as baseTest, beforeEach, describe, expect, vi } from "vitest";
|
|
3
|
-
import { AzureCloudAccountService } from "../cloud-account-service.js";
|
|
4
|
-
const { queryResources } = vi.hoisted(() => ({
|
|
5
|
-
queryResources: vi.fn().mockRejectedValue(new Error("Not implemented")),
|
|
6
|
-
}));
|
|
7
|
-
const { mockProviderGet, mockProviderRegister } = vi.hoisted(() => ({
|
|
8
|
-
mockProviderGet: vi
|
|
9
|
-
.fn()
|
|
10
|
-
.mockResolvedValue({ registrationState: "Registered" }),
|
|
11
|
-
mockProviderRegister: vi.fn().mockResolvedValue({}),
|
|
12
|
-
}));
|
|
13
|
-
const { mockRoleAssignmentsCreate, mockRoleAssignmentsListForScope } = vi.hoisted(() => ({
|
|
14
|
-
mockRoleAssignmentsCreate: vi.fn().mockResolvedValue({}),
|
|
15
|
-
mockRoleAssignmentsListForScope: vi.fn(),
|
|
16
|
-
}));
|
|
17
|
-
const { mockCreateFederatedIdentityCredential, mockCreateIdentity, mockCreateKeyVault, mockCreateResourceGroup, mockDeleteResourceGroup, mockGetSubscription, mockKeyVaultNameAvailability, mockSetSecret, } = vi.hoisted(() => ({
|
|
18
|
-
mockCreateFederatedIdentityCredential: vi.fn().mockResolvedValue({}),
|
|
19
|
-
mockCreateIdentity: vi
|
|
20
|
-
.fn()
|
|
21
|
-
.mockResolvedValue({ clientId: "client-1", principalId: "principal-1" }),
|
|
22
|
-
mockCreateKeyVault: vi.fn().mockResolvedValue({}),
|
|
23
|
-
mockCreateResourceGroup: vi.fn().mockResolvedValue({}),
|
|
24
|
-
mockDeleteResourceGroup: vi.fn().mockResolvedValue({}),
|
|
25
|
-
mockGetSubscription: vi.fn().mockResolvedValue({ tenantId: "tenant-1" }),
|
|
26
|
-
mockKeyVaultNameAvailability: vi.fn().mockResolvedValue({
|
|
27
|
-
nameAvailable: true,
|
|
28
|
-
}),
|
|
29
|
-
mockSetSecret: vi.fn().mockResolvedValue({}),
|
|
30
|
-
}));
|
|
31
|
-
vi.mock("@azure/arm-authorization", () => ({
|
|
32
|
-
AuthorizationManagementClient: class {
|
|
33
|
-
roleAssignments = {
|
|
34
|
-
create: mockRoleAssignmentsCreate,
|
|
35
|
-
listForScope: mockRoleAssignmentsListForScope,
|
|
36
|
-
};
|
|
37
|
-
},
|
|
38
|
-
}));
|
|
39
|
-
vi.mock("@azure/arm-keyvault", () => ({
|
|
40
|
-
KeyVaultManagementClient: class {
|
|
41
|
-
vaults = {
|
|
42
|
-
beginCreateOrUpdateAndWait: mockCreateKeyVault,
|
|
43
|
-
checkNameAvailability: mockKeyVaultNameAvailability,
|
|
44
|
-
};
|
|
45
|
-
},
|
|
46
|
-
}));
|
|
47
|
-
vi.mock("@azure/arm-msi", () => ({
|
|
48
|
-
ManagedServiceIdentityClient: class {
|
|
49
|
-
federatedIdentityCredentials = {
|
|
50
|
-
createOrUpdate: mockCreateFederatedIdentityCredential,
|
|
51
|
-
};
|
|
52
|
-
userAssignedIdentities = {
|
|
53
|
-
createOrUpdate: mockCreateIdentity,
|
|
54
|
-
};
|
|
55
|
-
},
|
|
56
|
-
}));
|
|
57
|
-
vi.mock("@azure/identity", () => ({
|
|
58
|
-
DefaultAzureCredential: vi.fn(),
|
|
59
|
-
}));
|
|
60
|
-
vi.mock("@azure/arm-resourcegraph", () => ({
|
|
61
|
-
ResourceGraphClient: class {
|
|
62
|
-
resources = queryResources;
|
|
63
|
-
},
|
|
64
|
-
}));
|
|
65
|
-
vi.mock("@azure/arm-resources", () => ({
|
|
66
|
-
ResourceManagementClient: class {
|
|
67
|
-
providers = {
|
|
68
|
-
get: mockProviderGet,
|
|
69
|
-
register: mockProviderRegister,
|
|
70
|
-
};
|
|
71
|
-
resourceGroups = {
|
|
72
|
-
beginDeleteAndWait: mockDeleteResourceGroup,
|
|
73
|
-
createOrUpdate: mockCreateResourceGroup,
|
|
74
|
-
};
|
|
75
|
-
},
|
|
76
|
-
}));
|
|
77
|
-
vi.mock("@azure/arm-resources-subscriptions", () => ({
|
|
78
|
-
SubscriptionClient: class {
|
|
79
|
-
subscriptions = {
|
|
80
|
-
get: mockGetSubscription,
|
|
81
|
-
};
|
|
82
|
-
},
|
|
83
|
-
}));
|
|
84
|
-
vi.mock("@azure/keyvault-secrets", () => ({
|
|
85
|
-
SecretClient: class {
|
|
86
|
-
setSecret = mockSetSecret;
|
|
87
|
-
},
|
|
88
|
-
}));
|
|
89
|
-
const test = baseTest.extend({
|
|
90
|
-
// the empty pattern is required by vitest!!!
|
|
91
|
-
// eslint-disable-next-line no-empty-pattern
|
|
92
|
-
cloudAccountService: async ({}, use) => {
|
|
93
|
-
const cloudAccountService = new AzureCloudAccountService(new DefaultAzureCredential());
|
|
94
|
-
await use(cloudAccountService);
|
|
95
|
-
},
|
|
96
|
-
});
|
|
97
|
-
beforeEach(() => {
|
|
98
|
-
queryResources.mockReset();
|
|
99
|
-
queryResources.mockResolvedValue({ data: [], totalRecords: 0 });
|
|
100
|
-
mockCreateFederatedIdentityCredential.mockClear();
|
|
101
|
-
mockCreateIdentity.mockClear();
|
|
102
|
-
mockCreateIdentity.mockResolvedValue({
|
|
103
|
-
clientId: "client-1",
|
|
104
|
-
principalId: "principal-1",
|
|
105
|
-
});
|
|
106
|
-
mockCreateKeyVault.mockClear();
|
|
107
|
-
mockCreateResourceGroup.mockClear();
|
|
108
|
-
mockDeleteResourceGroup.mockClear();
|
|
109
|
-
mockGetSubscription.mockClear();
|
|
110
|
-
mockGetSubscription.mockResolvedValue({ tenantId: "tenant-1" });
|
|
111
|
-
mockKeyVaultNameAvailability.mockClear();
|
|
112
|
-
mockKeyVaultNameAvailability.mockResolvedValue({ nameAvailable: true });
|
|
113
|
-
mockProviderGet.mockClear();
|
|
114
|
-
mockProviderGet.mockResolvedValue({ registrationState: "Registered" });
|
|
115
|
-
mockProviderRegister.mockClear();
|
|
116
|
-
mockRoleAssignmentsCreate.mockClear();
|
|
117
|
-
mockRoleAssignmentsListForScope.mockReset();
|
|
118
|
-
mockSetSecret.mockClear();
|
|
119
|
-
});
|
|
120
|
-
describe("getTerraformBackend", () => {
|
|
121
|
-
test("returns undefined when no matching storage account is found", async ({ cloudAccountService, }) => {
|
|
122
|
-
queryResources.mockResolvedValueOnce({
|
|
123
|
-
data: [],
|
|
124
|
-
totalRecords: 0,
|
|
125
|
-
});
|
|
126
|
-
const result = await cloudAccountService.getTerraformBackend("sub-1", {
|
|
127
|
-
name: "dev",
|
|
128
|
-
prefix: "dx",
|
|
129
|
-
});
|
|
130
|
-
expect(result).toBeUndefined();
|
|
131
|
-
});
|
|
132
|
-
test("return the only matching storage account", async ({ cloudAccountService, }) => {
|
|
133
|
-
queryResources.mockResolvedValueOnce({
|
|
134
|
-
data: [
|
|
135
|
-
{
|
|
136
|
-
location: "italynorth",
|
|
137
|
-
name: "dxditntfstatest01",
|
|
138
|
-
resourceGroup: "dx-d-itn-tfstate-rg-01",
|
|
139
|
-
subscriptionId: "sub-1",
|
|
140
|
-
type: "microsoft.storage/storageaccounts",
|
|
141
|
-
},
|
|
142
|
-
],
|
|
143
|
-
totalRecords: 1,
|
|
144
|
-
});
|
|
145
|
-
const result = await cloudAccountService.getTerraformBackend("sub-1", {
|
|
146
|
-
name: "dev",
|
|
147
|
-
prefix: "dx",
|
|
148
|
-
});
|
|
149
|
-
expect(result).toEqual(expect.objectContaining({
|
|
150
|
-
resourceGroupName: "dx-d-itn-tfstate-rg-01",
|
|
151
|
-
storageAccountName: "dxditntfstatest01",
|
|
152
|
-
type: "azurerm",
|
|
153
|
-
}));
|
|
154
|
-
});
|
|
155
|
-
test("returns the best matching storage account among multiple", async ({ cloudAccountService, }) => {
|
|
156
|
-
queryResources.mockResolvedValueOnce({
|
|
157
|
-
data: [
|
|
158
|
-
{
|
|
159
|
-
location: "italynorth",
|
|
160
|
-
name: "dxditntfstatest01",
|
|
161
|
-
resourceGroup: "dx-d-itn-tfstate-rg-01",
|
|
162
|
-
subscriptionId: "sub-1",
|
|
163
|
-
type: "microsoft.storage/storageaccounts",
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
location: "italynorth",
|
|
167
|
-
name: "dxditntfstatest02",
|
|
168
|
-
resourceGroup: "dx-d-itn-tfstate-rg-01",
|
|
169
|
-
subscriptionId: "sub-1",
|
|
170
|
-
type: "microsoft.storage/storageaccounts",
|
|
171
|
-
},
|
|
172
|
-
{
|
|
173
|
-
location: "westeurope",
|
|
174
|
-
name: "dxdweutfstatest01",
|
|
175
|
-
resourceGroup: "dx-d-weu-tfstate-rg-01",
|
|
176
|
-
subscriptionId: "sub-1",
|
|
177
|
-
type: "microsoft.storage/storageaccounts",
|
|
178
|
-
},
|
|
179
|
-
],
|
|
180
|
-
totalRecords: 3,
|
|
181
|
-
});
|
|
182
|
-
const result = await cloudAccountService.getTerraformBackend("sub-1", {
|
|
183
|
-
name: "dev",
|
|
184
|
-
prefix: "dx",
|
|
185
|
-
});
|
|
186
|
-
expect(result).toEqual(expect.objectContaining({
|
|
187
|
-
resourceGroupName: "dx-d-itn-tfstate-rg-01",
|
|
188
|
-
storageAccountName: "dxditntfstatest02",
|
|
189
|
-
type: "azurerm",
|
|
190
|
-
}));
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
describe("isInitialized", () => {
|
|
194
|
-
test("returns true when both bootstrap identity and common Key Vault exist and all providers are registered", async ({ cloudAccountService, }) => {
|
|
195
|
-
// First call: identity query → found
|
|
196
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
|
|
197
|
-
// Second call: key vault query → found
|
|
198
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
|
|
199
|
-
// Provider checks → all registered (default mock)
|
|
200
|
-
const result = await cloudAccountService.isInitialized("sub-1", {
|
|
201
|
-
name: "dev",
|
|
202
|
-
prefix: "dx",
|
|
203
|
-
});
|
|
204
|
-
expect(result).toBe(true);
|
|
205
|
-
});
|
|
206
|
-
test("returns false when bootstrap identity exists but common Key Vault does not", async ({ cloudAccountService, }) => {
|
|
207
|
-
// First call: identity query → found
|
|
208
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
|
|
209
|
-
// Second call: key vault query → not found
|
|
210
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 0 });
|
|
211
|
-
const result = await cloudAccountService.isInitialized("sub-1", {
|
|
212
|
-
name: "dev",
|
|
213
|
-
prefix: "dx",
|
|
214
|
-
});
|
|
215
|
-
expect(result).toBe(false);
|
|
216
|
-
});
|
|
217
|
-
test("returns false when common Key Vault exists but bootstrap identity does not", async ({ cloudAccountService, }) => {
|
|
218
|
-
// First call: identity query → not found
|
|
219
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 0 });
|
|
220
|
-
// Second call: key vault query → found
|
|
221
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
|
|
222
|
-
const result = await cloudAccountService.isInitialized("sub-1", {
|
|
223
|
-
name: "dev",
|
|
224
|
-
prefix: "dx",
|
|
225
|
-
});
|
|
226
|
-
expect(result).toBe(false);
|
|
227
|
-
});
|
|
228
|
-
test("returns false when resources exist but a required provider is not registered", async ({ cloudAccountService, }) => {
|
|
229
|
-
// Both resources exist
|
|
230
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
|
|
231
|
-
queryResources.mockResolvedValueOnce({ data: [], totalRecords: 1 });
|
|
232
|
-
// One provider is not registered
|
|
233
|
-
mockProviderGet.mockResolvedValueOnce({
|
|
234
|
-
registrationState: "NotRegistered",
|
|
235
|
-
});
|
|
236
|
-
const result = await cloudAccountService.isInitialized("sub-1", {
|
|
237
|
-
name: "dev",
|
|
238
|
-
prefix: "dx",
|
|
239
|
-
});
|
|
240
|
-
expect(result).toBe(false);
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
describe("initialize", () => {
|
|
244
|
-
test("assigns bootstrap roles and creates bootstrap environment secrets", async ({ cloudAccountService, }) => {
|
|
245
|
-
const createOrUpdateEnvironmentSecret = vi
|
|
246
|
-
.fn()
|
|
247
|
-
.mockResolvedValue(undefined);
|
|
248
|
-
await cloudAccountService.initialize({
|
|
249
|
-
csp: "azure",
|
|
250
|
-
defaultLocation: "italynorth",
|
|
251
|
-
displayName: "Test subscription",
|
|
252
|
-
id: "sub-1",
|
|
253
|
-
}, {
|
|
254
|
-
name: "dev",
|
|
255
|
-
prefix: "dx",
|
|
256
|
-
}, {
|
|
257
|
-
clientId: "app-client-id",
|
|
258
|
-
id: "app-id",
|
|
259
|
-
installationId: "installation-id",
|
|
260
|
-
key: "private-key\n",
|
|
261
|
-
}, {
|
|
262
|
-
owner: "pagopa",
|
|
263
|
-
repo: "dx",
|
|
264
|
-
}, {
|
|
265
|
-
createBranch: vi.fn(),
|
|
266
|
-
createOrUpdateEnvironmentSecret,
|
|
267
|
-
createPullRequest: vi.fn(),
|
|
268
|
-
getFileContent: vi.fn(),
|
|
269
|
-
getRepository: vi.fn(),
|
|
270
|
-
updateFile: vi.fn(),
|
|
271
|
-
});
|
|
272
|
-
expect(mockRoleAssignmentsCreate).toHaveBeenCalledTimes(3);
|
|
273
|
-
expect(mockRoleAssignmentsCreate).toHaveBeenCalledWith("/subscriptions/sub-1", expect.any(String), expect.objectContaining({
|
|
274
|
-
principalId: "principal-1",
|
|
275
|
-
principalType: "ServicePrincipal",
|
|
276
|
-
roleDefinitionId: "/subscriptions/sub-1/providers/Microsoft.Authorization/roleDefinitions/f58310d9-a9f6-439a-9e8d-f62e7b41a168",
|
|
277
|
-
}));
|
|
278
|
-
expect(mockRoleAssignmentsCreate).toHaveBeenCalledWith("/subscriptions/sub-1", expect.any(String), expect.objectContaining({
|
|
279
|
-
principalId: "principal-1",
|
|
280
|
-
principalType: "ServicePrincipal",
|
|
281
|
-
roleDefinitionId: "/subscriptions/sub-1/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c",
|
|
282
|
-
}));
|
|
283
|
-
expect(mockRoleAssignmentsCreate).toHaveBeenCalledWith("/subscriptions/sub-1", expect.any(String), expect.objectContaining({
|
|
284
|
-
principalId: "principal-1",
|
|
285
|
-
principalType: "ServicePrincipal",
|
|
286
|
-
roleDefinitionId: "/subscriptions/sub-1/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe",
|
|
287
|
-
}));
|
|
288
|
-
expect(mockCreateFederatedIdentityCredential).toHaveBeenCalledWith("dx-d-itn-common-rg-01", "dx-d-itn-bootstrap-id-01", "dx-bootstrapper-dev-cd", {
|
|
289
|
-
audiences: ["api://AzureADTokenExchange"],
|
|
290
|
-
issuer: "https://token.actions.githubusercontent.com",
|
|
291
|
-
subject: "repo:pagopa/dx:environment:bootstrapper-dev-cd",
|
|
292
|
-
});
|
|
293
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledTimes(7);
|
|
294
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
|
|
295
|
-
environmentName: "bootstrapper-dev-cd",
|
|
296
|
-
owner: "pagopa",
|
|
297
|
-
repo: "dx",
|
|
298
|
-
secretName: "ARM_CLIENT_ID",
|
|
299
|
-
secretValue: "client-1",
|
|
300
|
-
});
|
|
301
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
|
|
302
|
-
environmentName: "bootstrapper-dev-cd",
|
|
303
|
-
owner: "pagopa",
|
|
304
|
-
repo: "dx",
|
|
305
|
-
secretName: "ARM_TENANT_ID",
|
|
306
|
-
secretValue: "tenant-1",
|
|
307
|
-
});
|
|
308
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
|
|
309
|
-
environmentName: "bootstrapper-dev-cd",
|
|
310
|
-
owner: "pagopa",
|
|
311
|
-
repo: "dx",
|
|
312
|
-
secretName: "ARM_SUBSCRIPTION_ID",
|
|
313
|
-
secretValue: "sub-1",
|
|
314
|
-
});
|
|
315
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
|
|
316
|
-
environmentName: "bootstrapper-dev-cd",
|
|
317
|
-
owner: "pagopa",
|
|
318
|
-
repo: "dx",
|
|
319
|
-
secretName: "GH_APP_ID",
|
|
320
|
-
secretValue: "app-id",
|
|
321
|
-
});
|
|
322
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
|
|
323
|
-
environmentName: "bootstrapper-dev-cd",
|
|
324
|
-
owner: "pagopa",
|
|
325
|
-
repo: "dx",
|
|
326
|
-
secretName: "GH_APP_CLIENT_ID",
|
|
327
|
-
secretValue: "app-client-id",
|
|
328
|
-
});
|
|
329
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
|
|
330
|
-
environmentName: "bootstrapper-dev-cd",
|
|
331
|
-
owner: "pagopa",
|
|
332
|
-
repo: "dx",
|
|
333
|
-
secretName: "GH_APP_INSTALLATION_ID",
|
|
334
|
-
secretValue: "installation-id",
|
|
335
|
-
});
|
|
336
|
-
expect(createOrUpdateEnvironmentSecret).toHaveBeenCalledWith({
|
|
337
|
-
environmentName: "bootstrapper-dev-cd",
|
|
338
|
-
owner: "pagopa",
|
|
339
|
-
repo: "dx",
|
|
340
|
-
secretName: "GH_APP_KEY",
|
|
341
|
-
secretValue: "private-key",
|
|
342
|
-
});
|
|
343
|
-
});
|
|
344
|
-
test("uses a repository-specific federated credential name", async ({ cloudAccountService, }) => {
|
|
345
|
-
const createOrUpdateEnvironmentSecret = vi
|
|
346
|
-
.fn()
|
|
347
|
-
.mockResolvedValue(undefined);
|
|
348
|
-
await cloudAccountService.initialize({
|
|
349
|
-
csp: "azure",
|
|
350
|
-
defaultLocation: "italynorth",
|
|
351
|
-
displayName: "Test subscription",
|
|
352
|
-
id: "sub-1",
|
|
353
|
-
}, {
|
|
354
|
-
name: "dev",
|
|
355
|
-
prefix: "dx",
|
|
356
|
-
}, {
|
|
357
|
-
clientId: "app-client-id",
|
|
358
|
-
id: "app-id",
|
|
359
|
-
installationId: "installation-id",
|
|
360
|
-
key: "private-key\n",
|
|
361
|
-
}, {
|
|
362
|
-
owner: "pagopa",
|
|
363
|
-
repo: "dx-playground",
|
|
364
|
-
}, {
|
|
365
|
-
createBranch: vi.fn(),
|
|
366
|
-
createOrUpdateEnvironmentSecret,
|
|
367
|
-
createPullRequest: vi.fn(),
|
|
368
|
-
getFileContent: vi.fn(),
|
|
369
|
-
getRepository: vi.fn(),
|
|
370
|
-
updateFile: vi.fn(),
|
|
371
|
-
});
|
|
372
|
-
expect(mockCreateFederatedIdentityCredential).toHaveBeenCalledWith("dx-d-itn-common-rg-01", "dx-d-itn-bootstrap-id-01", "dx-playground-bootstrapper-dev-cd", {
|
|
373
|
-
audiences: ["api://AzureADTokenExchange"],
|
|
374
|
-
issuer: "https://token.actions.githubusercontent.com",
|
|
375
|
-
subject: "repo:pagopa/dx-playground:environment:bootstrapper-dev-cd",
|
|
376
|
-
});
|
|
377
|
-
});
|
|
378
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { ok } from "neverthrow";
|
|
2
|
-
import { describe, expect, it, vi } from "vitest";
|
|
3
|
-
import { LocalCodemodRegistry } from "../registry.js";
|
|
4
|
-
describe("LocalCodemodRegistry", () => {
|
|
5
|
-
const makeCodemod = (id, description = id) => ({
|
|
6
|
-
apply: vi.fn().mockResolvedValue(undefined),
|
|
7
|
-
description,
|
|
8
|
-
id,
|
|
9
|
-
});
|
|
10
|
-
it("returns empty list when no codemods are registered", async () => {
|
|
11
|
-
const registry = new LocalCodemodRegistry();
|
|
12
|
-
const result = await registry.getAll();
|
|
13
|
-
expect(result).toStrictEqual(ok([]));
|
|
14
|
-
});
|
|
15
|
-
it("adds codemods and lists them via getAll", async () => {
|
|
16
|
-
const registry = new LocalCodemodRegistry();
|
|
17
|
-
const a = makeCodemod("a", "A");
|
|
18
|
-
const b = makeCodemod("b", "B");
|
|
19
|
-
registry.add(a);
|
|
20
|
-
registry.add(b);
|
|
21
|
-
const result = await registry.getAll();
|
|
22
|
-
expect.assertions(3);
|
|
23
|
-
expect(result.isOk()).toBe(true);
|
|
24
|
-
const expected = result.unwrapOr([]);
|
|
25
|
-
expect(expected).toHaveLength(2);
|
|
26
|
-
expect(expected).toEqual(expect.arrayContaining([
|
|
27
|
-
expect.objectContaining({ id: "a" }),
|
|
28
|
-
expect.objectContaining({ id: "b" }),
|
|
29
|
-
]));
|
|
30
|
-
});
|
|
31
|
-
it("retrieves a codemod by id and returns undefined when missing", async () => {
|
|
32
|
-
const registry = new LocalCodemodRegistry();
|
|
33
|
-
const a = makeCodemod("a", "A");
|
|
34
|
-
registry.add(a);
|
|
35
|
-
const found = await registry.getById("a");
|
|
36
|
-
expect(found.isOk()).toBe(true);
|
|
37
|
-
const expected = found.unwrapOr(undefined);
|
|
38
|
-
expect(expected).toBe(a);
|
|
39
|
-
const missing = await registry.getById("nope");
|
|
40
|
-
expect(missing.isOk()).toBe(true);
|
|
41
|
-
const missingValue = missing.unwrapOr(undefined);
|
|
42
|
-
expect(missingValue).toBeUndefined();
|
|
43
|
-
});
|
|
44
|
-
it("overwrites an existing codemod when adding with the same id", async () => {
|
|
45
|
-
const registry = new LocalCodemodRegistry();
|
|
46
|
-
const first = makeCodemod("a", "first");
|
|
47
|
-
const second = makeCodemod("a", "second");
|
|
48
|
-
registry.add(first);
|
|
49
|
-
registry.add(second);
|
|
50
|
-
const byId = await registry.getById("a");
|
|
51
|
-
expect(byId.isOk()).toBe(true);
|
|
52
|
-
const byIdValue = byId.unwrapOr(undefined);
|
|
53
|
-
expect(byIdValue).toBe(second);
|
|
54
|
-
expect(byIdValue).not.toBe(first);
|
|
55
|
-
});
|
|
56
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
import { describe, expect, it } from "vitest";
|
|
2
|
-
import { migrateWorkflow } from "../use-azure-appsvc.js";
|
|
3
|
-
describe("migrateWorkflow", () => {
|
|
4
|
-
const sha = "testsha";
|
|
5
|
-
const migrate = migrateWorkflow(sha);
|
|
6
|
-
it("adds disable_auto_staging_deploy under with for web_app_deploy", () => {
|
|
7
|
-
const input = `
|
|
8
|
-
jobs:
|
|
9
|
-
deploy:
|
|
10
|
-
uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
|
|
11
|
-
with:
|
|
12
|
-
web_app_name: my-app
|
|
13
|
-
use_staging_slot: true
|
|
14
|
-
`;
|
|
15
|
-
const output = migrate(input, "workflow.yaml");
|
|
16
|
-
expect(output).toContain("disable_auto_staging_deploy: true");
|
|
17
|
-
});
|
|
18
|
-
it("adds disable_auto_staging_deploy under with for function_app_deploy", () => {
|
|
19
|
-
const input = `
|
|
20
|
-
jobs:
|
|
21
|
-
deploy:
|
|
22
|
-
uses: pagopa/dx/.github/workflows/function_app_deploy.yaml@main
|
|
23
|
-
with:
|
|
24
|
-
function_app_name: my-func
|
|
25
|
-
use_staging_slot: true
|
|
26
|
-
`;
|
|
27
|
-
const output = migrate(input, "workflow.yaml");
|
|
28
|
-
expect(output).toContain("disable_auto_staging_deploy: true");
|
|
29
|
-
});
|
|
30
|
-
it("renames function_app_name to web_app_name", () => {
|
|
31
|
-
const input = `
|
|
32
|
-
jobs:
|
|
33
|
-
deploy:
|
|
34
|
-
uses: pagopa/dx/.github/workflows/function_app_deploy.yaml@main
|
|
35
|
-
with:
|
|
36
|
-
function_app_name: my-func
|
|
37
|
-
`;
|
|
38
|
-
const output = migrate(input, "workflow.yaml");
|
|
39
|
-
expect(output).toContain("web_app_name: my-func");
|
|
40
|
-
expect(output).not.toContain("function_app_name:");
|
|
41
|
-
});
|
|
42
|
-
it("removes use_staging_slot", () => {
|
|
43
|
-
const input = `
|
|
44
|
-
jobs:
|
|
45
|
-
deploy:
|
|
46
|
-
uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
|
|
47
|
-
with:
|
|
48
|
-
web_app_name: my-app
|
|
49
|
-
use_staging_slot: true
|
|
50
|
-
`;
|
|
51
|
-
const output = migrate(input, "workflow.yaml");
|
|
52
|
-
expect(output).not.toContain("use_staging_slot:");
|
|
53
|
-
});
|
|
54
|
-
it("updates uses to release-azure-appsvc.yaml@sha", () => {
|
|
55
|
-
const input = `
|
|
56
|
-
jobs:
|
|
57
|
-
deploy:
|
|
58
|
-
uses: pagopa/dx/.github/workflows/web_app_deploy.yaml@main
|
|
59
|
-
with:
|
|
60
|
-
web_app_name: my-app
|
|
61
|
-
`;
|
|
62
|
-
const output = migrate(input, "workflow.yaml");
|
|
63
|
-
expect(output).toContain(`uses: pagopa/dx/.github/workflows/release-azure-appsvc-v1.yaml@${sha}`);
|
|
64
|
-
});
|
|
65
|
-
it("does not change unrelated workflows", () => {
|
|
66
|
-
const input = `
|
|
67
|
-
jobs:
|
|
68
|
-
build:
|
|
69
|
-
runs-on: ubuntu-latest
|
|
70
|
-
steps:
|
|
71
|
-
- name: Checkout
|
|
72
|
-
uses: actions/checkout@v3
|
|
73
|
-
`;
|
|
74
|
-
const output = migrate(input, "workflow.yaml");
|
|
75
|
-
expect(output).toBe(input);
|
|
76
|
-
});
|
|
77
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|