@fabrika/provider-zerops 0.7.0 → 0.8.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/package.json +9 -9
- package/src/control.ts +7 -3
- package/src/index.ts +2 -2
- package/src/namespace/proxy-reads.ts +25 -14
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fabrika/provider-zerops",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"zod": "^3.25.76",
|
|
46
|
-
"@fabrika/auth": "0.
|
|
47
|
-
"@fabrika/auth-core": "0.
|
|
48
|
-
"@fabrika/email": "0.
|
|
49
|
-
"@fabrika/iam-contract": "0.
|
|
50
|
-
"@fabrika/installation-init": "0.
|
|
51
|
-
"@fabrika/operations-contract": "0.
|
|
52
|
-
"@fabrika/provider-contract": "0.
|
|
53
|
-
"@fabrika/proxy-core": "0.
|
|
46
|
+
"@fabrika/auth": "0.8.0",
|
|
47
|
+
"@fabrika/auth-core": "0.8.0",
|
|
48
|
+
"@fabrika/email": "0.8.0",
|
|
49
|
+
"@fabrika/iam-contract": "0.8.0",
|
|
50
|
+
"@fabrika/installation-init": "0.8.0",
|
|
51
|
+
"@fabrika/operations-contract": "0.8.0",
|
|
52
|
+
"@fabrika/provider-contract": "0.8.0",
|
|
53
|
+
"@fabrika/proxy-core": "0.8.0",
|
|
54
54
|
"yaml": "^2.9.1"
|
|
55
55
|
}
|
|
56
56
|
}
|
package/src/control.ts
CHANGED
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
type ZeropsNamespaceTarget,
|
|
49
49
|
zeropsNamespaceTargetCodec,
|
|
50
50
|
} from './namespace'
|
|
51
|
-
import { assertNamespaceProxyReads, type
|
|
51
|
+
import { assertNamespaceProxyReads, type OlderProxyReaders } from './namespace/proxy-reads'
|
|
52
52
|
import { createZeropsDeployer, ZEROPS_VERSION_DEADLINE_MS } from './provider'
|
|
53
53
|
import { allowedReferenceHosts, assertNoPlatformOnlyReference, foreignReferenceHost, serviceReferenceHosts } from './service-references'
|
|
54
54
|
import { normalizeZeropsSourceRepository } from './source'
|
|
@@ -102,8 +102,8 @@ export interface ZeropsControlProviderOptions {
|
|
|
102
102
|
readonly proxySource: ZeropsNamespaceProxySource
|
|
103
103
|
readonly iamUrl: string
|
|
104
104
|
readonly iamKey: string
|
|
105
|
-
/** The
|
|
106
|
-
readonly olderProxies:
|
|
105
|
+
/** The manifest parsers of the older releases' proxies, which a namespace pinned to an older source may run. */
|
|
106
|
+
readonly olderProxies: OlderProxyReaders
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
@@ -340,6 +340,10 @@ export const createZeropsControlProvider = (options: ZeropsControlProviderOption
|
|
|
340
340
|
}
|
|
341
341
|
},
|
|
342
342
|
resolveSource,
|
|
343
|
+
validateAccess: ({ environment, access }) => {
|
|
344
|
+
const placement = resolvedEnvironment(environment, { requireReady: true })
|
|
345
|
+
assertNamespaceProxyReads(placement.namespace.id, access, placement.namespaceTarget.proxySource, options.namespaces)
|
|
346
|
+
},
|
|
343
347
|
deploy: async (input: ProviderDeployInput): Promise<ProviderDeployOutcome> => {
|
|
344
348
|
input.signal.throwIfAborted()
|
|
345
349
|
assertAuthoredManagedInputs({ variableNames: Object.keys(input.vars), secretNames: Object.keys(input.secrets) })
|
package/src/index.ts
CHANGED
|
@@ -101,8 +101,8 @@ export type {
|
|
|
101
101
|
ZeropsProxyRepublishInput,
|
|
102
102
|
} from './namespace'
|
|
103
103
|
export { postgresSchema as zeropsNamespacePostgresSchema } from './namespace/codec'
|
|
104
|
-
export {
|
|
105
|
-
export type {
|
|
104
|
+
export { entriesNeedingCurrentProxy } from './namespace/proxy-reads'
|
|
105
|
+
export type { OlderProxyReader, OlderProxyReaders } from './namespace/proxy-reads'
|
|
106
106
|
export { buildZeropsPlan, resolveDeployHostname } from './plan'
|
|
107
107
|
export type { ZeropsStep, ZeropsStepKind } from './plan'
|
|
108
108
|
export { CANCELLED, createZeropsDeployer, interpolateManifest } from './provider'
|
|
@@ -1,35 +1,46 @@
|
|
|
1
1
|
// What a namespace proxy pinned to an older source cannot read. Its manifest parser is strict: one row of a form it does
|
|
2
|
-
// not know
|
|
3
|
-
// deploy that would publish
|
|
2
|
+
// not know, or a CSP directive it does not know, refuses the whole manifest and blocks the namespace's next republish.
|
|
3
|
+
// So a deploy that would publish either is refused before publication while the namespace's proxy source is not
|
|
4
|
+
// this control plane's own.
|
|
4
5
|
|
|
5
6
|
import type { ProviderApprovedAccess } from '@fabrika/provider-contract'
|
|
7
|
+
import type { CspOrigins } from '@fabrika/proxy-core/headers'
|
|
6
8
|
import { contractProxyTable, type ProxyEndpointRow } from '@fabrika/proxy-core/manifest'
|
|
7
9
|
import type { ZeropsNamespaceProxySource } from './types'
|
|
8
10
|
|
|
9
|
-
/**
|
|
10
|
-
|
|
11
|
+
/**
|
|
12
|
+
* What the namespace proxy of one older platform release parses of an application's manifest entry: a row, and the
|
|
13
|
+
* entry's CSP directives, each by that release's own parser.
|
|
14
|
+
*/
|
|
15
|
+
export interface OlderProxyReader {
|
|
16
|
+
readonly row: (row: ProxyEndpointRow) => boolean
|
|
17
|
+
readonly csp: (csp: CspOrigins) => boolean
|
|
18
|
+
}
|
|
11
19
|
|
|
12
20
|
/**
|
|
13
21
|
* The namespace proxies of the older releases this platform serves (ADR-0062). Control holds their parsers, as it holds
|
|
14
|
-
* their contract readers; a pin's release is not recorded, so
|
|
22
|
+
* their contract readers; a pin's release is not recorded, so what any of them reads is what the pin may read.
|
|
15
23
|
*/
|
|
16
|
-
export type
|
|
24
|
+
export type OlderProxyReaders = readonly [OlderProxyReader, ...OlderProxyReader[]]
|
|
17
25
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
/**
|
|
27
|
+
* What of the approved contract's manifest entry no older release's proxy parses, as the namespace publishes it: each
|
|
28
|
+
* such row by its id, and `csp` when no older proxy parses the entry's CSP (`workerSrc`, which only this release knows).
|
|
29
|
+
*/
|
|
30
|
+
export function entriesNeedingCurrentProxy(access: ProviderApprovedAccess, olderProxies: OlderProxyReaders): string[] {
|
|
31
|
+
const table = contractProxyTable(access.contract, access.contractDigest)
|
|
32
|
+
const rows = table.endpoints.filter((row) => !olderProxies.some((proxy) => proxy.row(row))).map((row) => row.id)
|
|
33
|
+
return olderProxies.some((proxy) => proxy.csp(table.csp)) ? rows : [...rows, 'csp']
|
|
23
34
|
}
|
|
24
35
|
|
|
25
36
|
/** This control plane's own proxy source, and the parsers of the older releases a pinned proxy may run. */
|
|
26
37
|
export interface PlatformProxies {
|
|
27
38
|
readonly proxySource: ZeropsNamespaceProxySource
|
|
28
|
-
readonly olderProxies:
|
|
39
|
+
readonly olderProxies: OlderProxyReaders
|
|
29
40
|
}
|
|
30
41
|
|
|
31
42
|
/**
|
|
32
|
-
* Refuses a deploy whose approved contract holds a row the namespace's pinned proxy may not read: its source is not the
|
|
43
|
+
* Refuses a deploy whose approved contract holds a row or a CSP directive the namespace's pinned proxy may not read: its source is not the
|
|
33
44
|
* one this control plane deploys new placements from. `platform` is absent where this control plane manages no
|
|
34
45
|
* namespace proxy, which then has nothing to compare.
|
|
35
46
|
*/
|
|
@@ -42,7 +53,7 @@ export function assertNamespaceProxyReads(
|
|
|
42
53
|
if (access === undefined || platform === undefined || pinned.commitSha === platform.proxySource.commitSha) {
|
|
43
54
|
return
|
|
44
55
|
}
|
|
45
|
-
const rows =
|
|
56
|
+
const rows = entriesNeedingCurrentProxy(access, platform.olderProxies)
|
|
46
57
|
if (rows.length === 0) {
|
|
47
58
|
return
|
|
48
59
|
}
|