@fabrika/provider-zerops 0.0.15 → 0.0.16

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabrika/provider-zerops",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "type": "module",
5
5
  "repository": {
6
6
  "type": "git",
@@ -32,9 +32,9 @@
32
32
  "gen:schema": "bun scripts/generate-zerops-types.ts"
33
33
  },
34
34
  "dependencies": {
35
- "@fabrika/auth": "^0.0.15",
36
- "@fabrika/auth-core": "^0.0.15",
37
- "@fabrika/provider-contract": "^0.0.15",
38
- "@fabrika/proxy-contract": "^0.0.15"
35
+ "@fabrika/auth": "^0.0.16",
36
+ "@fabrika/auth-core": "^0.0.16",
37
+ "@fabrika/provider-contract": "^0.0.16",
38
+ "@fabrika/proxy-contract": "^0.0.16"
39
39
  }
40
40
  }
package/src/index.ts CHANGED
@@ -69,6 +69,7 @@ export {
69
69
  compileZeropsNamespaceTopology,
70
70
  createZeropsNamespaceCapabilities,
71
71
  createZeropsNamespaceOperator,
72
+ ensureNamespaceProxyIam,
72
73
  ZEROPS_NAMESPACE_IAM_ISSUER_VARIABLE,
73
74
  ZEROPS_NAMESPACE_IAM_KEY_VARIABLE,
74
75
  ZEROPS_NAMESPACE_POSTGRES_HOSTNAME,
@@ -78,6 +79,7 @@ export {
78
79
  zeropsNamespaceTargetCodec,
79
80
  } from './namespace'
80
81
  export type {
82
+ NamespaceProxyIamInput,
81
83
  ZeropsNamespaceOperatorOptions,
82
84
  ZeropsNamespaceOptions,
83
85
  ZeropsNamespacePlanOptions,
package/src/namespace.ts CHANGED
@@ -737,6 +737,47 @@ const resolveServices = async (
737
737
  return postgres === null ? { proxy } : { proxy, postgres }
738
738
  }
739
739
 
740
+ export interface NamespaceProxyIamInput {
741
+ readonly api: Pick<ZeropsApi, 'listServiceEnv' | 'putServiceEnv'>
742
+ readonly proxyServiceId: string
743
+ /** The public IAM origin the proxy compares a token's `iss` against. */
744
+ readonly iamUrl: string
745
+ readonly iamKey: string
746
+ readonly signal: AbortSignal
747
+ }
748
+
749
+ /**
750
+ * Converge the two variables the namespace proxy's own CODE reads, and call this from everywhere that
751
+ * code is replaced — not only where the namespace is created.
752
+ *
753
+ * `syncZeropsProxy` rebuilds the proxy from git on every app deploy, so a proxy can take new code
754
+ * whose configuration nobody rewrote. That is not hypothetical: the `FABRIKA_IAM_URL` →
755
+ * `FABRIKA_IAM_ISSUER` rename ([ADR-0035](../../../docs/decisions/0035-the-platform-owns-the-application-iam-issuer.md))
756
+ * left a live namespace proxy crash-looping on `FABRIKA_IAM_ISSUER is required`, because provisioning
757
+ * had written the old name months earlier and the deploy path only ever wrote the manifest. Writing
758
+ * these BEFORE the pipeline is triggered is what makes a rename a flag day rather than an outage
759
+ * ([ADR-0024](../../../docs/decisions/0024-retire-the-legacy-environment-name-fallback.md)).
760
+ */
761
+ export const ensureNamespaceProxyIam = async (input: NamespaceProxyIamInput): Promise<void> => {
762
+ const variables = await input.api.listServiceEnv({ serviceId: input.proxyServiceId, signal: input.signal })
763
+ const issuer = variables.find((variable) => variable.key === ZEROPS_NAMESPACE_IAM_ISSUER_VARIABLE)
764
+ if (issuer?.content !== input.iamUrl) {
765
+ await input.api.putServiceEnv({
766
+ serviceId: input.proxyServiceId,
767
+ key: ZEROPS_NAMESPACE_IAM_ISSUER_VARIABLE,
768
+ value: input.iamUrl,
769
+ signal: input.signal,
770
+ })
771
+ }
772
+ // Secret read-back is not trustworthy, so overwrite it idempotently without inspecting its value.
773
+ await input.api.putServiceEnv({
774
+ serviceId: input.proxyServiceId,
775
+ key: ZEROPS_NAMESPACE_IAM_KEY_VARIABLE,
776
+ value: input.iamKey,
777
+ signal: input.signal,
778
+ })
779
+ }
780
+
740
781
  const ensureProxyConfiguration = async (
741
782
  target: NormalizedZeropsNamespaceTarget,
742
783
  options: ZeropsNamespaceOptions,
@@ -759,20 +800,11 @@ const ensureProxyConfiguration = async (
759
800
  })
760
801
  deployRequired = true
761
802
  }
762
- const iamUrl = byKey.get(ZEROPS_NAMESPACE_IAM_ISSUER_VARIABLE)
763
- if (iamUrl?.content !== options.iamUrl) {
764
- await options.api.putServiceEnv({
765
- serviceId: proxyServiceId,
766
- key: ZEROPS_NAMESPACE_IAM_ISSUER_VARIABLE,
767
- value: options.iamUrl,
768
- signal,
769
- })
770
- }
771
- // Secret read-back is not trustworthy, so overwrite it idempotently without inspecting its value.
772
- await options.api.putServiceEnv({
773
- serviceId: proxyServiceId,
774
- key: ZEROPS_NAMESPACE_IAM_KEY_VARIABLE,
775
- value: options.iamKey,
803
+ await ensureNamespaceProxyIam({
804
+ api: options.api,
805
+ proxyServiceId,
806
+ iamUrl: options.iamUrl,
807
+ iamKey: options.iamKey,
776
808
  signal,
777
809
  })
778
810
  return deployRequired