@ankhorage/infra 6.0.0 → 7.1.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/CHANGELOG.md +12 -0
- package/README.md +1 -1
- package/dist/cli/commands/destroy.d.ts.map +1 -1
- package/dist/cli/commands/destroy.js +1 -0
- package/dist/cli/commands/destroy.js.map +1 -1
- package/dist/cli/utils/prepareInfraCommandOperationAsync.d.ts.map +1 -1
- package/dist/cli/utils/prepareInfraCommandOperationAsync.js +4 -1
- package/dist/cli/utils/prepareInfraCommandOperationAsync.js.map +1 -1
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.d.ts.map +1 -1
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.js +33 -10
- package/dist/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.js.map +1 -1
- package/dist/features/environment-lifecycle/adapters/outbound/createProjectInfraCredentialPort.d.ts +11 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createProjectInfraCredentialPort.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createProjectInfraCredentialPort.js +125 -0
- package/dist/features/environment-lifecycle/adapters/outbound/createProjectInfraCredentialPort.js.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraCredentialsAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraCredentialsAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraCredentialsAsync.js +9 -0
- package/dist/features/environment-lifecycle/adapters/outbound/removeStoredInfraCredentialsAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraServicesAsync.d.ts +4 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraServicesAsync.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraServicesAsync.js +15 -0
- package/dist/features/environment-lifecycle/application/use-cases/prepareInfraServicesAsync.js.map +1 -0
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.d.ts +1 -1
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.d.ts.map +1 -1
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.js +10 -5
- package/dist/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.js.map +1 -1
- package/dist/features/environment-lifecycle/composition/createInfraCommandServices.d.ts.map +1 -1
- package/dist/features/environment-lifecycle/composition/createInfraCommandServices.js +9 -3
- package/dist/features/environment-lifecycle/composition/createInfraCommandServices.js.map +1 -1
- package/dist/features/environment-lifecycle/composition/createProjectInfraLifecycle.d.ts.map +1 -1
- package/dist/features/environment-lifecycle/composition/createProjectInfraLifecycle.js +28 -2
- package/dist/features/environment-lifecycle/composition/createProjectInfraLifecycle.js.map +1 -1
- package/dist/features/environment-lifecycle/utils/resolveInfraEnvironmentStateDirectory.d.ts +4 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraEnvironmentStateDirectory.d.ts.map +1 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraEnvironmentStateDirectory.js +11 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraEnvironmentStateDirectory.js.map +1 -0
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.d.ts +1 -1
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.d.ts.map +1 -1
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.js +2 -6
- package/dist/features/environment-lifecycle/utils/resolveInfraStatePath.js.map +1 -1
- package/dist/types/infraCli.d.ts +7 -1
- package/dist/types/infraCli.d.ts.map +1 -1
- package/dist/types/infraCli.js.map +1 -1
- package/package.json +3 -2
- package/src/cli/commands/destroy.ts +1 -0
- package/src/cli/utils/prepareInfraCommandOperationAsync.ts +4 -1
- package/src/environmentCredentialPort.test.ts +62 -0
- package/src/features/environment-lifecycle/adapters/outbound/createEnvironmentInfraCredentialPort.ts +55 -18
- package/src/features/environment-lifecycle/adapters/outbound/createProjectInfraCredentialPort.ts +182 -0
- package/src/features/environment-lifecycle/adapters/outbound/removeStoredInfraCredentialsAsync.ts +18 -0
- package/src/features/environment-lifecycle/application/use-cases/prepareInfraServicesAsync.ts +23 -0
- package/src/features/environment-lifecycle/application/use-cases/upInfraEnvironmentAsync.ts +8 -4
- package/src/features/environment-lifecycle/composition/createInfraCommandServices.ts +9 -3
- package/src/features/environment-lifecycle/composition/createProjectInfraLifecycle.ts +33 -4
- package/src/features/environment-lifecycle/utils/resolveInfraEnvironmentStateDirectory.ts +16 -0
- package/src/features/environment-lifecycle/utils/resolveInfraStatePath.ts +3 -6
- package/src/infraUp.test.ts +31 -3
- package/src/prepareInfraServices.test.ts +50 -0
- package/src/projectCredentialLifecycle.test.ts +161 -0
- package/src/projectCredentialStore.test.ts +151 -0
- package/src/types/infraCli.ts +11 -1
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
InfraControlPlaneCredentialRef,
|
|
7
|
+
InfraEnvironmentSpec,
|
|
8
|
+
InfraLedger,
|
|
9
|
+
InfraResult,
|
|
10
|
+
} from '@ankhorage/contracts/infra';
|
|
11
|
+
import { expect, it, mock } from 'bun:test';
|
|
12
|
+
|
|
13
|
+
import { createProjectInfraCredentialPort } from './features/environment-lifecycle/adapters/outbound/createProjectInfraCredentialPort.js';
|
|
14
|
+
import { createProjectInfraLifecycle } from './project/index.js';
|
|
15
|
+
import type { InfraLifecycleOperations } from './types/infraCli.js';
|
|
16
|
+
|
|
17
|
+
const bootstrap = {
|
|
18
|
+
source: 'control-plane',
|
|
19
|
+
name: 'FIXTURE_BOOTSTRAP',
|
|
20
|
+
} as const satisfies InfraControlPlaneCredentialRef;
|
|
21
|
+
const generated = { username: 'fixture', password: 'generated-secret' } as const;
|
|
22
|
+
const previewGenerated = { username: 'preview', password: 'preview-secret' } as const;
|
|
23
|
+
|
|
24
|
+
const desired = {
|
|
25
|
+
deployment: {
|
|
26
|
+
compute: { provider: 'local' },
|
|
27
|
+
runtime: { provider: 'docker-compose' },
|
|
28
|
+
},
|
|
29
|
+
} as const satisfies InfraEnvironmentSpec;
|
|
30
|
+
|
|
31
|
+
const ledger = {
|
|
32
|
+
schemaVersion: 1,
|
|
33
|
+
projectId: 'sample',
|
|
34
|
+
environment: 'local',
|
|
35
|
+
targets: [],
|
|
36
|
+
resources: [],
|
|
37
|
+
outputs: [],
|
|
38
|
+
artifacts: [],
|
|
39
|
+
} as const satisfies InfraLedger;
|
|
40
|
+
|
|
41
|
+
it('persists provider-created credentials across up/down and removes only the destroyed environment', async () => {
|
|
42
|
+
await withTempProjectAsync(async (projectPath) => {
|
|
43
|
+
const generateCredential = mock(() => generated);
|
|
44
|
+
const operations = createCredentialOperations(generateCredential);
|
|
45
|
+
const request = {
|
|
46
|
+
projectId: 'sample',
|
|
47
|
+
projectPath,
|
|
48
|
+
manifest: { environments: { local: desired, preview: desired }, modules: [] },
|
|
49
|
+
environment: 'local' as const,
|
|
50
|
+
executionEnvironment: {},
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const firstLifecycle = createProjectInfraLifecycle({ services: { operations } });
|
|
54
|
+
const firstUp = await firstLifecycle.upAsync(request);
|
|
55
|
+
expect(firstUp.ok).toBe(true);
|
|
56
|
+
expect(generateCredential).toHaveBeenCalledTimes(1);
|
|
57
|
+
expect(JSON.stringify(firstUp)).not.toContain('generated-secret');
|
|
58
|
+
expect(await fs.readFile(statePath(projectPath, 'local'), 'utf8')).not.toContain(
|
|
59
|
+
'generated-secret',
|
|
60
|
+
);
|
|
61
|
+
|
|
62
|
+
const down = await firstLifecycle.downAsync(request);
|
|
63
|
+
expect(down.ok).toBe(true);
|
|
64
|
+
expect(await createPort(projectPath, 'local').resolveAsync(bootstrap)).toMatchObject({
|
|
65
|
+
ok: true,
|
|
66
|
+
value: generated,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const secondLifecycle = createProjectInfraLifecycle({ services: { operations } });
|
|
70
|
+
const secondUp = await secondLifecycle.upAsync(request);
|
|
71
|
+
expect(secondUp.ok).toBe(true);
|
|
72
|
+
expect(generateCredential).toHaveBeenCalledTimes(1);
|
|
73
|
+
expect(JSON.stringify(secondUp)).not.toContain('generated-secret');
|
|
74
|
+
|
|
75
|
+
const previewPort = createPort(projectPath, 'preview');
|
|
76
|
+
expect(await previewPort.persistAsync(bootstrap, previewGenerated)).toMatchObject({ ok: true });
|
|
77
|
+
|
|
78
|
+
const destroyed = await secondLifecycle.destroyAsync({
|
|
79
|
+
...request,
|
|
80
|
+
confirmation: { projectId: 'sample', environment: 'local' },
|
|
81
|
+
persistence: { policy: 'retain' },
|
|
82
|
+
});
|
|
83
|
+
expect(destroyed.ok).toBe(true);
|
|
84
|
+
expect(await createPort(projectPath, 'local').findAsync(bootstrap)).toEqual({
|
|
85
|
+
ok: true,
|
|
86
|
+
value: null,
|
|
87
|
+
diagnostics: [],
|
|
88
|
+
});
|
|
89
|
+
expect(await previewPort.resolveAsync(bootstrap)).toMatchObject({
|
|
90
|
+
ok: true,
|
|
91
|
+
value: previewGenerated,
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/*** Create provider-neutral operation fixtures that generate credentials only when lookup is missing. */
|
|
97
|
+
function createCredentialOperations(
|
|
98
|
+
generateCredential: () => Readonly<Record<string, string>>,
|
|
99
|
+
): InfraLifecycleOperations {
|
|
100
|
+
return {
|
|
101
|
+
validate: () => Promise.resolve(success({ environment: 'local' })),
|
|
102
|
+
plan: (request) =>
|
|
103
|
+
Promise.resolve(success({ projectId: request.projectId, environment: 'local', actions: [] })),
|
|
104
|
+
generate: () => Promise.resolve(success({ environment: 'local', artifacts: [], ledger })),
|
|
105
|
+
up: async (_request, dependencies) => {
|
|
106
|
+
const found = await dependencies.credentials.findAsync(bootstrap);
|
|
107
|
+
if (!found.ok) return { ok: false, diagnostics: found.diagnostics };
|
|
108
|
+
if (found.value === null) {
|
|
109
|
+
const persisted = await dependencies.credentials.persistAsync(
|
|
110
|
+
bootstrap,
|
|
111
|
+
generateCredential(),
|
|
112
|
+
);
|
|
113
|
+
if (!persisted.ok) return { ok: false, diagnostics: persisted.diagnostics };
|
|
114
|
+
}
|
|
115
|
+
return success({
|
|
116
|
+
environment: 'local',
|
|
117
|
+
targets: [],
|
|
118
|
+
resources: [],
|
|
119
|
+
outputs: [],
|
|
120
|
+
ledger,
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
status: (request) =>
|
|
124
|
+
Promise.resolve(
|
|
125
|
+
success({
|
|
126
|
+
projectId: request.projectId,
|
|
127
|
+
environment: 'local',
|
|
128
|
+
state: 'ready',
|
|
129
|
+
resources: [],
|
|
130
|
+
}),
|
|
131
|
+
),
|
|
132
|
+
outputs: () => success({ environment: 'local', outputs: [] }),
|
|
133
|
+
down: () => Promise.resolve(success({ environment: 'local', ledger })),
|
|
134
|
+
destroy: () => Promise.resolve(success({ environment: 'local', ledger: null })),
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/*** Create the real project-local credential adapter for one isolated test environment. */
|
|
139
|
+
function createPort(projectPath: string, environment: 'local' | 'preview') {
|
|
140
|
+
return createProjectInfraCredentialPort({ projectPath, environment, processEnvironment: {} });
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/*** Resolve the canonical Infra ownership-state path without touching credential storage internals. */
|
|
144
|
+
function statePath(projectPath: string, environment: 'local' | 'preview'): string {
|
|
145
|
+
return path.join(projectPath, '.ankh', 'infra', environment, 'state.json');
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/*** Create one successful Infra result for operation fixtures. */
|
|
149
|
+
function success<T>(value: T): InfraResult<T> {
|
|
150
|
+
return { ok: true, value, diagnostics: [] };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/*** Run one filesystem test against a disposable project root. */
|
|
154
|
+
async function withTempProjectAsync(run: (projectPath: string) => Promise<void>): Promise<void> {
|
|
155
|
+
const projectPath = await fs.mkdtemp(path.join(os.tmpdir(), 'ankh-infra-credential-lifecycle-'));
|
|
156
|
+
try {
|
|
157
|
+
await run(projectPath);
|
|
158
|
+
} finally {
|
|
159
|
+
await fs.rm(projectPath, { recursive: true, force: true });
|
|
160
|
+
}
|
|
161
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { promises as fs } from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
import type { InfraControlPlaneCredentialRef } from '@ankhorage/contracts/infra';
|
|
7
|
+
import { expect, it } from 'bun:test';
|
|
8
|
+
|
|
9
|
+
import { createProjectInfraCredentialPort } from './features/environment-lifecycle/adapters/outbound/createProjectInfraCredentialPort';
|
|
10
|
+
|
|
11
|
+
const bootstrap = reference('FIXTURE_BOOTSTRAP');
|
|
12
|
+
const secondary = reference('SECONDARY_BOOTSTRAP');
|
|
13
|
+
const generated = { username: 'fixture', password: 'generated-secret' } as const;
|
|
14
|
+
|
|
15
|
+
it('persists one opaque bundle and resolves it from a fresh host instance', async () => {
|
|
16
|
+
await withTempProjectAsync(async (projectPath) => {
|
|
17
|
+
const first = createPort(projectPath);
|
|
18
|
+
expect(await first.findAsync(bootstrap)).toEqual({ ok: true, value: null, diagnostics: [] });
|
|
19
|
+
expect(await first.persistAsync(bootstrap, generated)).toEqual({
|
|
20
|
+
ok: true,
|
|
21
|
+
value: null,
|
|
22
|
+
diagnostics: [],
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const fresh = createPort(projectPath);
|
|
26
|
+
expect(await fresh.resolveAsync(bootstrap)).toEqual({
|
|
27
|
+
ok: true,
|
|
28
|
+
value: generated,
|
|
29
|
+
diagnostics: [],
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('keeps exact and prefixed environment overrides ahead of persisted state', async () => {
|
|
35
|
+
await withTempProjectAsync(async (projectPath) => {
|
|
36
|
+
const stored = createPort(projectPath);
|
|
37
|
+
await stored.persistAsync(bootstrap, generated);
|
|
38
|
+
|
|
39
|
+
const exact = createPort(projectPath, {
|
|
40
|
+
FIXTURE_BOOTSTRAP: JSON.stringify({ username: 'exact', password: 'override' }),
|
|
41
|
+
ANKH_INFRA_CREDENTIAL_FIXTURE_BOOTSTRAP: JSON.stringify({
|
|
42
|
+
username: 'prefixed',
|
|
43
|
+
password: 'override',
|
|
44
|
+
}),
|
|
45
|
+
});
|
|
46
|
+
expect(await exact.resolveAsync(bootstrap)).toMatchObject({
|
|
47
|
+
ok: true,
|
|
48
|
+
value: { username: 'exact', password: 'override' },
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
const prefixed = createPort(projectPath, {
|
|
52
|
+
ANKH_INFRA_CREDENTIAL_FIXTURE_BOOTSTRAP: JSON.stringify({
|
|
53
|
+
username: 'prefixed',
|
|
54
|
+
password: 'override',
|
|
55
|
+
}),
|
|
56
|
+
});
|
|
57
|
+
expect(await prefixed.resolveAsync(bootstrap)).toMatchObject({
|
|
58
|
+
ok: true,
|
|
59
|
+
value: { username: 'prefixed', password: 'override' },
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('fails closed on malformed persisted state instead of treating it as missing', async () => {
|
|
65
|
+
await withTempProjectAsync(async (projectPath) => {
|
|
66
|
+
const port = createPort(projectPath);
|
|
67
|
+
await port.persistAsync(bootstrap, generated);
|
|
68
|
+
await fs.writeFile(credentialPath(projectPath, 'local', bootstrap.name), '{broken', 'utf8');
|
|
69
|
+
|
|
70
|
+
const result = await createPort(projectPath).findAsync(bootstrap);
|
|
71
|
+
expect(result.ok).toBe(false);
|
|
72
|
+
expect(result.diagnostics).toEqual([
|
|
73
|
+
{
|
|
74
|
+
severity: 'error',
|
|
75
|
+
code: 'infra-control-plane-credential-store-invalid',
|
|
76
|
+
message:
|
|
77
|
+
'Stored control-plane credential FIXTURE_BOOTSTRAP has an invalid project-state shape.',
|
|
78
|
+
},
|
|
79
|
+
]);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('uses restrictive permissions and leaves no partial files after concurrent writes', async () => {
|
|
84
|
+
await withTempProjectAsync(async (projectPath) => {
|
|
85
|
+
const port = createPort(projectPath);
|
|
86
|
+
await Promise.all([
|
|
87
|
+
port.persistAsync(bootstrap, generated),
|
|
88
|
+
port.persistAsync(secondary, { token: 'another-secret' }),
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
const directory = path.dirname(credentialPath(projectPath, 'local', bootstrap.name));
|
|
92
|
+
const entries = await fs.readdir(directory);
|
|
93
|
+
expect(entries.filter((entry) => entry.endsWith('.json'))).toHaveLength(2);
|
|
94
|
+
expect(entries.some((entry) => entry.endsWith('.tmp'))).toBe(false);
|
|
95
|
+
if (process.platform !== 'win32') {
|
|
96
|
+
expect((await fs.stat(directory)).mode & 0o777).toBe(0o700);
|
|
97
|
+
expect(
|
|
98
|
+
(await fs.stat(credentialPath(projectPath, 'local', bootstrap.name))).mode & 0o777,
|
|
99
|
+
).toBe(0o600);
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('isolates persisted credentials by project and environment', async () => {
|
|
105
|
+
await withTempProjectAsync(async (root) => {
|
|
106
|
+
const projectA = path.join(root, 'a');
|
|
107
|
+
const projectB = path.join(root, 'b');
|
|
108
|
+
const local = createPort(projectA);
|
|
109
|
+
const preview = createPort(projectA, {}, 'preview');
|
|
110
|
+
const otherProject = createPort(projectB);
|
|
111
|
+
await local.persistAsync(bootstrap, generated);
|
|
112
|
+
|
|
113
|
+
expect(await local.resolveAsync(bootstrap)).toMatchObject({ ok: true, value: generated });
|
|
114
|
+
expect(await preview.findAsync(bootstrap)).toEqual({ ok: true, value: null, diagnostics: [] });
|
|
115
|
+
expect(await otherProject.findAsync(bootstrap)).toEqual({
|
|
116
|
+
ok: true,
|
|
117
|
+
value: null,
|
|
118
|
+
diagnostics: [],
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
function createPort(
|
|
124
|
+
projectPath: string,
|
|
125
|
+
processEnvironment: Readonly<Record<string, string | undefined>> = {},
|
|
126
|
+
environment: 'local' | 'preview' = 'local',
|
|
127
|
+
) {
|
|
128
|
+
return createProjectInfraCredentialPort({ projectPath, environment, processEnvironment });
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function reference(name: string): InfraControlPlaneCredentialRef {
|
|
132
|
+
return { source: 'control-plane', name };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function credentialPath(
|
|
136
|
+
projectPath: string,
|
|
137
|
+
environment: 'local' | 'preview',
|
|
138
|
+
name: string,
|
|
139
|
+
): string {
|
|
140
|
+
const digest = createHash('sha256').update(name).digest('hex');
|
|
141
|
+
return path.join(projectPath, '.ankh', 'infra', environment, 'credentials', `${digest}.json`);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function withTempProjectAsync(run: (projectPath: string) => Promise<void>): Promise<void> {
|
|
145
|
+
const projectPath = await fs.mkdtemp(path.join(os.tmpdir(), 'ankh-infra-credentials-'));
|
|
146
|
+
try {
|
|
147
|
+
await run(projectPath);
|
|
148
|
+
} finally {
|
|
149
|
+
await fs.rm(projectPath, { recursive: true, force: true });
|
|
150
|
+
}
|
|
151
|
+
}
|
package/src/types/infraCli.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { AppEnvironmentId } from '@ankhorage/contracts/environments';
|
|
|
3
3
|
import type { InfraEnvironmentSpec } from '@ankhorage/contracts/infra';
|
|
4
4
|
|
|
5
5
|
import type { readStoredInfraStateAsync } from '../features/environment-lifecycle/adapters/outbound/readStoredInfraStateAsync.js';
|
|
6
|
+
import type { removeStoredInfraCredentialsAsync } from '../features/environment-lifecycle/adapters/outbound/removeStoredInfraCredentialsAsync.js';
|
|
6
7
|
import type { removeStoredInfraStateAsync } from '../features/environment-lifecycle/adapters/outbound/removeStoredInfraStateAsync.js';
|
|
7
8
|
import type { writeInfraGeneratedArtifactsAsync } from '../features/environment-lifecycle/adapters/outbound/writeInfraGeneratedArtifactsAsync.js';
|
|
8
9
|
import type { writeStoredInfraStateAsync } from '../features/environment-lifecycle/adapters/outbound/writeStoredInfraStateAsync.js';
|
|
@@ -79,6 +80,11 @@ export interface InfraLifecycleOperations {
|
|
|
79
80
|
readonly destroy: typeof destroyInfraEnvironmentAsync;
|
|
80
81
|
}
|
|
81
82
|
|
|
83
|
+
interface InfraDependencyScope {
|
|
84
|
+
readonly projectPath: string;
|
|
85
|
+
readonly environment: AppEnvironmentId;
|
|
86
|
+
}
|
|
87
|
+
|
|
82
88
|
export interface InfraCommandServices {
|
|
83
89
|
readonly resolveProject: (options: {
|
|
84
90
|
readonly cwd: string;
|
|
@@ -87,9 +93,13 @@ export interface InfraCommandServices {
|
|
|
87
93
|
readonly readState: typeof readStoredInfraStateAsync;
|
|
88
94
|
readonly writeState: typeof writeStoredInfraStateAsync;
|
|
89
95
|
readonly removeState: typeof removeStoredInfraStateAsync;
|
|
96
|
+
readonly removeCredentials: typeof removeStoredInfraCredentialsAsync;
|
|
90
97
|
readonly writeArtifacts: typeof writeInfraGeneratedArtifactsAsync;
|
|
91
98
|
readonly operations: InfraLifecycleOperations;
|
|
92
|
-
readonly createDependencies: (
|
|
99
|
+
readonly createDependencies: (
|
|
100
|
+
context: InfraCommandContext,
|
|
101
|
+
scope: InfraDependencyScope,
|
|
102
|
+
) => InfraOrchestrationDependencies;
|
|
93
103
|
}
|
|
94
104
|
|
|
95
105
|
export interface RunInfraCommandOptions {
|