@intentius/chant-lexicon-sql 0.124.54 → 0.124.55

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.
Files changed (61) hide show
  1. package/dist/capability-plugin.d.ts +160 -0
  2. package/dist/capability-plugin.d.ts.map +1 -0
  3. package/dist/capability-plugin.js +370 -0
  4. package/dist/change-set.d.ts +35 -0
  5. package/dist/change-set.d.ts.map +1 -1
  6. package/dist/change-set.js +43 -0
  7. package/dist/ci-setup.d.ts +34 -0
  8. package/dist/ci-setup.d.ts.map +1 -0
  9. package/dist/ci-setup.js +106 -0
  10. package/dist/clickhouse/access.d.ts +20 -0
  11. package/dist/clickhouse/access.d.ts.map +1 -1
  12. package/dist/clickhouse/access.js +42 -1
  13. package/dist/clickhouse/live/describe-resources.d.ts +3 -1
  14. package/dist/clickhouse/live/describe-resources.d.ts.map +1 -1
  15. package/dist/clickhouse/live/describe-resources.js +31 -3
  16. package/dist/clickhouse/plan/deep.d.ts +42 -11
  17. package/dist/clickhouse/plan/deep.d.ts.map +1 -1
  18. package/dist/clickhouse/plan/deep.js +104 -33
  19. package/dist/exit-codes.d.ts +69 -0
  20. package/dist/exit-codes.d.ts.map +1 -0
  21. package/dist/exit-codes.js +105 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +12 -0
  25. package/dist/integrity.json +2 -2
  26. package/dist/lock-grain.d.ts +27 -0
  27. package/dist/lock-grain.d.ts.map +1 -0
  28. package/dist/lock-grain.js +13 -0
  29. package/dist/manifest.json +1 -1
  30. package/dist/plugin.d.ts.map +1 -1
  31. package/dist/plugin.js +8 -0
  32. package/dist/postgres/testing/migration.d.ts +2 -0
  33. package/dist/postgres/testing/migration.d.ts.map +1 -1
  34. package/dist/token-source.d.ts +28 -0
  35. package/dist/token-source.d.ts.map +1 -1
  36. package/dist/token-source.js +70 -1
  37. package/dist/yodel-run.d.ts +58 -0
  38. package/dist/yodel-run.d.ts.map +1 -0
  39. package/dist/yodel-run.js +145 -0
  40. package/package.json +2 -2
  41. package/src/capability-plugin.test.ts +317 -0
  42. package/src/capability-plugin.ts +515 -0
  43. package/src/change-set.ts +74 -0
  44. package/src/ci-setup.test.ts +67 -0
  45. package/src/ci-setup.ts +116 -0
  46. package/src/clickhouse/access.ts +49 -2
  47. package/src/clickhouse/live/access.e2e.test.ts +8 -7
  48. package/src/clickhouse/live/describe-resources.ts +27 -3
  49. package/src/clickhouse/plan/deep-grants-drift.test.ts +151 -0
  50. package/src/clickhouse/plan/deep-grants.test.ts +10 -5
  51. package/src/clickhouse/plan/deep.ts +103 -32
  52. package/src/exit-codes.test.ts +46 -0
  53. package/src/exit-codes.ts +140 -0
  54. package/src/index.ts +28 -0
  55. package/src/lock-grain.test.ts +57 -0
  56. package/src/lock-grain.ts +37 -0
  57. package/src/plugin.ts +9 -0
  58. package/src/testdata/fake-yodel.mjs +58 -0
  59. package/src/token-source-traded.test.ts +75 -0
  60. package/src/token-source.ts +74 -1
  61. package/src/yodel-run.ts +175 -0
@@ -0,0 +1,69 @@
1
+ /**
2
+ * SQL engine outcomes mapped onto chant's exit-code table (#4553, `CHANT_EXIT`
3
+ * in `@intentius/chant/exit-codes`), for the versioned migration engine chant
4
+ * runs through the sql capability (sql-yodeler, `yodel`).
5
+ *
6
+ * sql-yodeler from sql-yodeler#288 on exits by chant's table, so its codes
7
+ * pass through. An older yodel has its own table, where 3 means anything
8
+ * outstanding (lint errors included) and 4 every refusal; {@link yodelExitOf}
9
+ * reads one of those with the command it came from.
10
+ *
11
+ * | Engine outcome | Table |
12
+ * |---|---|
13
+ * | applied, nothing pending, stood down at plan time | `done` |
14
+ * | a wave plan that moved (`WavePlanMoved`), an approval of another digest | `moved` |
15
+ * | a policy rule denies the plan and no override counts | `denied` |
16
+ * | another apply holds the history lock | `held` |
17
+ * | a newer commit on the branch applies the same environment (stand-down) | `superseded` |
18
+ * | an apply stopped at its gate, pending migrations under `yodel status`, a migration the required environment has not applied, a change that needs an Op the engine does not run, a manual step | `waiting` |
19
+ * | drift found by `yodel drift` | `drift` |
20
+ * | a checksum mismatch, a fork, an out-of-order migration, an applied migration gone from the directory, reader and writer one identity, a write run with the reader, lint errors | `failed` |
21
+ */
22
+ import { type ChantExitCode } from "@intentius/chant/exit-codes";
23
+ /** An outcome of the versioned migration engine, by name. */
24
+ export type SqlEngineOutcome = "applied" | "unchanged" | "plan-moved" | "approval-moved" | "policy-denied" | "lock-held" | "stood-down" | "gated" | "pending" | "promotion-unmet" | "needs-op" | "manual-step" | "drift" | "checksum-mismatch" | "fork" | "out-of-order" | "directory" | "shared-identity" | "reader-write" | "lint-errors" | "failed";
25
+ /**
26
+ * The table's code for an engine outcome. A refusal no approval fixes is
27
+ * `failed`; one a person can clear (a gate, an unmet promotion) is `waiting`.
28
+ */
29
+ export declare function sqlExitOf(outcome: SqlEngineOutcome): ChantExitCode;
30
+ /** Whether `outcome` is a plan that moved since its approval. */
31
+ export declare function sqlPlanMoved(outcome: SqlEngineOutcome): boolean;
32
+ /** yodel's own exit table before sql-yodeler#288 (its `src/exit.ts` up to 0.10). */
33
+ export declare const YODEL_LEGACY_EXIT: {
34
+ readonly ok: 0;
35
+ readonly error: 1;
36
+ /** Something yodel will not do itself; drift, for `yodel drift`. */
37
+ readonly needsOp: 2;
38
+ /** Something outstanding: a gate, pending migrations, lint errors. */
39
+ readonly outstanding: 3;
40
+ /** Refused, nothing done: every refusal, policy denials and unmet promotions included. */
41
+ readonly refused: 4;
42
+ readonly locked: 5;
43
+ };
44
+ /** A `yodel` exit status and the command it came from. */
45
+ export interface YodelExitSource {
46
+ code: number | null | undefined;
47
+ /** The yodel verb (`apply`, `status`, `lint`, `drift`, ...). */
48
+ command?: string;
49
+ /** The yodel predates sql-yodeler#288 and exits by {@link YODEL_LEGACY_EXIT}. */
50
+ legacy?: boolean;
51
+ }
52
+ /**
53
+ * The table's code for a `yodel` exit status. A yodel on chant's table passes
54
+ * through (a code outside the table is `failed`). A legacy yodel's codes are
55
+ * read by meaning:
56
+ *
57
+ * | legacy yodel | Table |
58
+ * |---|---|
59
+ * | 0 | `done` |
60
+ * | 2 from `yodel drift` | `drift` |
61
+ * | 2 from any other verb, a change that needs an Op or a manual step | `waiting` |
62
+ * | 3 from `yodel lint` | `failed` (sql-yodeler#285 ruling C) |
63
+ * | 3 from any other verb | `waiting` |
64
+ * | 4, any refusal | `failed`: the legacy code does not tell a policy denial or an unmet promotion apart |
65
+ * | 5 | `held` |
66
+ * | 1, anything else | `failed` |
67
+ */
68
+ export declare function yodelExitOf(source: YodelExitSource): ChantExitCode;
69
+ //# sourceMappingURL=exit-codes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.d.ts","sourceRoot":"","sources":["../src/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAc,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAE7E,6DAA6D;AAC7D,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,WAAW,GACX,YAAY,GACZ,gBAAgB,GAChB,eAAe,GACf,WAAW,GACX,YAAY,GACZ,OAAO,GACP,SAAS,GACT,iBAAiB,GACjB,UAAU,GACV,aAAa,GACb,OAAO,GACP,mBAAmB,GACnB,MAAM,GACN,cAAc,GACd,WAAW,GACX,iBAAiB,GACjB,cAAc,GACd,aAAa,GACb,QAAQ,CAAC;AA0Bb;;;GAGG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAElE;AAED,iEAAiE;AACjE,wBAAgB,YAAY,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAE/D;AAED,oFAAoF;AACpF,eAAO,MAAM,iBAAiB;;;IAG5B,oEAAoE;;IAEpE,sEAAsE;;IAEtE,0FAA0F;;;CAGlF,CAAC;AAEX,0DAA0D;AAC1D,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAChC,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,eAAe,GAAG,aAAa,CAiBlE"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * SQL engine outcomes mapped onto chant's exit-code table (#4553, `CHANT_EXIT`
3
+ * in `@intentius/chant/exit-codes`), for the versioned migration engine chant
4
+ * runs through the sql capability (sql-yodeler, `yodel`).
5
+ *
6
+ * sql-yodeler from sql-yodeler#288 on exits by chant's table, so its codes
7
+ * pass through. An older yodel has its own table, where 3 means anything
8
+ * outstanding (lint errors included) and 4 every refusal; {@link yodelExitOf}
9
+ * reads one of those with the command it came from.
10
+ *
11
+ * | Engine outcome | Table |
12
+ * |---|---|
13
+ * | applied, nothing pending, stood down at plan time | `done` |
14
+ * | a wave plan that moved (`WavePlanMoved`), an approval of another digest | `moved` |
15
+ * | a policy rule denies the plan and no override counts | `denied` |
16
+ * | another apply holds the history lock | `held` |
17
+ * | a newer commit on the branch applies the same environment (stand-down) | `superseded` |
18
+ * | an apply stopped at its gate, pending migrations under `yodel status`, a migration the required environment has not applied, a change that needs an Op the engine does not run, a manual step | `waiting` |
19
+ * | drift found by `yodel drift` | `drift` |
20
+ * | a checksum mismatch, a fork, an out-of-order migration, an applied migration gone from the directory, reader and writer one identity, a write run with the reader, lint errors | `failed` |
21
+ */
22
+ import { CHANT_EXIT } from "@intentius/chant/exit-codes";
23
+ const OUTCOME_EXIT = {
24
+ applied: CHANT_EXIT.done,
25
+ unchanged: CHANT_EXIT.done,
26
+ "plan-moved": CHANT_EXIT.moved,
27
+ "approval-moved": CHANT_EXIT.moved,
28
+ "policy-denied": CHANT_EXIT.denied,
29
+ "lock-held": CHANT_EXIT.held,
30
+ "stood-down": CHANT_EXIT.superseded,
31
+ gated: CHANT_EXIT.waiting,
32
+ pending: CHANT_EXIT.waiting,
33
+ "promotion-unmet": CHANT_EXIT.waiting,
34
+ "needs-op": CHANT_EXIT.waiting,
35
+ "manual-step": CHANT_EXIT.waiting,
36
+ drift: CHANT_EXIT.drift,
37
+ "checksum-mismatch": CHANT_EXIT.failed,
38
+ fork: CHANT_EXIT.failed,
39
+ "out-of-order": CHANT_EXIT.failed,
40
+ directory: CHANT_EXIT.failed,
41
+ "shared-identity": CHANT_EXIT.failed,
42
+ "reader-write": CHANT_EXIT.failed,
43
+ "lint-errors": CHANT_EXIT.failed,
44
+ failed: CHANT_EXIT.failed,
45
+ };
46
+ /**
47
+ * The table's code for an engine outcome. A refusal no approval fixes is
48
+ * `failed`; one a person can clear (a gate, an unmet promotion) is `waiting`.
49
+ */
50
+ export function sqlExitOf(outcome) {
51
+ return OUTCOME_EXIT[outcome];
52
+ }
53
+ /** Whether `outcome` is a plan that moved since its approval. */
54
+ export function sqlPlanMoved(outcome) {
55
+ return sqlExitOf(outcome) === CHANT_EXIT.moved;
56
+ }
57
+ /** yodel's own exit table before sql-yodeler#288 (its `src/exit.ts` up to 0.10). */
58
+ export const YODEL_LEGACY_EXIT = {
59
+ ok: 0,
60
+ error: 1,
61
+ /** Something yodel will not do itself; drift, for `yodel drift`. */
62
+ needsOp: 2,
63
+ /** Something outstanding: a gate, pending migrations, lint errors. */
64
+ outstanding: 3,
65
+ /** Refused, nothing done: every refusal, policy denials and unmet promotions included. */
66
+ refused: 4,
67
+ locked: 5,
68
+ };
69
+ /**
70
+ * The table's code for a `yodel` exit status. A yodel on chant's table passes
71
+ * through (a code outside the table is `failed`). A legacy yodel's codes are
72
+ * read by meaning:
73
+ *
74
+ * | legacy yodel | Table |
75
+ * |---|---|
76
+ * | 0 | `done` |
77
+ * | 2 from `yodel drift` | `drift` |
78
+ * | 2 from any other verb, a change that needs an Op or a manual step | `waiting` |
79
+ * | 3 from `yodel lint` | `failed` (sql-yodeler#285 ruling C) |
80
+ * | 3 from any other verb | `waiting` |
81
+ * | 4, any refusal | `failed`: the legacy code does not tell a policy denial or an unmet promotion apart |
82
+ * | 5 | `held` |
83
+ * | 1, anything else | `failed` |
84
+ */
85
+ export function yodelExitOf(source) {
86
+ const { code, command, legacy } = source;
87
+ if (code === 0)
88
+ return CHANT_EXIT.done;
89
+ if (!legacy) {
90
+ for (const value of Object.values(CHANT_EXIT))
91
+ if (value === code)
92
+ return value;
93
+ return CHANT_EXIT.failed;
94
+ }
95
+ switch (code) {
96
+ case YODEL_LEGACY_EXIT.needsOp:
97
+ return command === "drift" ? CHANT_EXIT.drift : CHANT_EXIT.waiting;
98
+ case YODEL_LEGACY_EXIT.outstanding:
99
+ return command === "lint" ? CHANT_EXIT.failed : CHANT_EXIT.waiting;
100
+ case YODEL_LEGACY_EXIT.locked:
101
+ return CHANT_EXIT.held;
102
+ default:
103
+ return CHANT_EXIT.failed;
104
+ }
105
+ }
package/dist/index.d.ts CHANGED
@@ -6,4 +6,8 @@ export { database, table, view, dictionary, user, role, policy, quota, settingsP
6
6
  export { schema, index, sequence, type, domain, extension, func, procedure, aggregate, trigger, eventTrigger, operator, operatorClass, operatorFamily, foreignTable, textSearchConfiguration, textSearchDictionary, statistics, foreignDataWrapper, foreignServer, publication, collation, cast } from "./postgres/entities.js";
7
7
  export { diffStatements, renderStatements, type DiffStatementsOptions, type ManualStep, type MigrationStep, type OpStep, type SchemaStatements, type StatementChange, type StatementStep, type StepObject, } from "./migration-statements.js";
8
8
  export { readSqlFile, sqlFileDeclarations, sqlFileEntities, sqlFileOf, SqlFileError, type SqlFileObject, type SqlFileOptions, type SqlFileSource, } from "./sql-files.js";
9
+ export { sqlExitOf, sqlPlanMoved, yodelExitOf, YODEL_LEGACY_EXIT, type SqlEngineOutcome, type YodelExitSource } from "./exit-codes.js";
10
+ export { sqlCapabilityPlugin, sqlMigrateCapability, sqlApplyCapability, createSqlMigrateCapability, createSqlApplyCapability, SqlPlanMovedError, YodelRunError, SQL_VERB_FAMILIES, type SqlMigrateStepInput, type SqlMigrateStepOutput, type SqlMigrateArtifact, type SqlApplyStepInput, type SqlApplyStepOutput, } from "./capability-plugin.js";
11
+ export { sqlDefaultLockGrain, sqlLockGrainRefusal, type SqlLockGrainKind } from "./lock-grain.js";
12
+ export { YODEL_COMMANDS, YODEL_OPTIONAL_FLAGS, runAllowedYodel, allowedYodelArgv, type YodelRunner, type YodelRun } from "./yodel-run.js";
9
13
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAM3D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAMtI,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,UAAU,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAI7T,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,KAAK,SAAS,EAAE,MAAM,UAAU,CAAC;AAM3D,OAAO,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAMtI,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,UAAU,EAAE,kBAAkB,EAAE,aAAa,EAAE,WAAW,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAC;AAI7T,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,KAAK,qBAAqB,EAC1B,KAAK,UAAU,EACf,KAAK,aAAa,EAClB,KAAK,MAAM,EACX,KAAK,gBAAgB,EACrB,KAAK,eAAe,EACpB,KAAK,aAAa,EAClB,KAAK,UAAU,GAChB,MAAM,wBAAwB,CAAC;AAIhC,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,YAAY,EACZ,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAOpI,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,0BAA0B,EAC1B,wBAAwB,EACxB,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EACjB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EACzB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,GACxB,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,KAAK,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,eAAe,EAAE,gBAAgB,EAAE,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -22,3 +22,15 @@ export { diffStatements, renderStatements, } from "./migration-statements.js";
22
22
  // Plain `.sql` files as a schema source (#3646): DDL read into the declarations
23
23
  // the tagged templates make; also at `@intentius/chant-lexicon-sql/sql-files`.
24
24
  export { readSqlFile, sqlFileDeclarations, sqlFileEntities, sqlFileOf, SqlFileError, } from "./sql-files.js";
25
+ // SQL engine and yodel outcomes on chant's exit-code table (#4570); also at
26
+ // `@intentius/chant-lexicon-sql/exit-codes`.
27
+ export { sqlExitOf, sqlPlanMoved, yodelExitOf, YODEL_LEGACY_EXIT } from "./exit-codes.js";
28
+ // The `sql-migrate` and `sql-apply` capabilities (#4569), contributed to core's
29
+ // capability-plugin seam: core loads `sqlCapabilityPlugin` when a project's
30
+ // chant.config lists this lexicon, so op waves and pr-plan plan and apply a
31
+ // SQL member through chant. sql-yodeler's engine runs by a fixed argv list
32
+ // (`YODEL_COMMANDS`).
33
+ export { sqlCapabilityPlugin, sqlMigrateCapability, sqlApplyCapability, createSqlMigrateCapability, createSqlApplyCapability, SqlPlanMovedError, YodelRunError, SQL_VERB_FAMILIES, } from "./capability-plugin.js";
34
+ // The lock grain of a SQL member (#4571): target, with resource refused by name.
35
+ export { sqlDefaultLockGrain, sqlLockGrainRefusal } from "./lock-grain.js";
36
+ export { YODEL_COMMANDS, YODEL_OPTIONAL_FLAGS, runAllowedYodel, allowedYodelArgv } from "./yodel-run.js";
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "algorithm": "sha256",
3
3
  "artifacts": {
4
- "manifest.json": "1c5c80cc89bf89d0e69689cc3bed3bc3a1220b8805edfaf5ad5c41ac44fa051c",
4
+ "manifest.json": "1fde954d33c814b24fa348430a4727deee6a4e503c95c56a4db27e45e1edb016",
5
5
  "meta.json": "2a75a38ea0fb186f27a59d6b8401d7af0809db5e471769f0259f7c1a4292b858",
6
6
  "types/index.d.ts": "0286ebb367773e84c76818b0f69cb14cff8328fd2f8c65ed87563c8d5815458c",
7
7
  "rules/postgres-templates.ts": "cbbe8b3c3531300ef5f17d596bf9403343d9fde019961436b6af0cdc66e4064a",
@@ -80,5 +80,5 @@
80
80
  "rules/sqlpg125.ts": "cc7411c57c525613dc720ba00e986bbc4e5a84b8b0bcfa7a6ce0d058f039f025",
81
81
  "rules/sqlpg126.ts": "d57b82a5842273876510131d67bf4418cbd61eff821e245edebc644dafd502bb"
82
82
  },
83
- "composite": "9c591c97c31e3e6d029ba0138be4f1b960b1cffc50e41fd9de201b60af44fc83"
83
+ "composite": "108fefe2f3370008e48604e44a74f1e5a4d767b8fbc72d33fa55616e6e67c15f"
84
84
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * The lock grain of a SQL member (#4571, on #4552's hooks).
3
+ *
4
+ * A SQL member's grain is `target`: one environment's history. Two applies
5
+ * of one environment are kept apart by the environment's own lock, which
6
+ * sql-yodeler takes for every apply (a KeeperMap row on ClickHouse, a
7
+ * session advisory lock on Postgres), and by chant's target lock on the
8
+ * environment. `sql-apply` sends a whole build in creation order, so it
9
+ * holds the environment too.
10
+ *
11
+ * `resource` is refused by name, as it is on Terraform and stock Pulumi: a
12
+ * migration chain applies in order, and a row per object would let two
13
+ * applies of one chain interleave. Neither kind answers `lockRows`. `repo`
14
+ * is the pipeline's, and any member may take it.
15
+ *
16
+ * sql-yodeler's rendered apply jobs set `APPLY_LOCK` (`YODEL_LOCK_WAIT`,
17
+ * `YODEL_STAND_DOWN`, src/ci/render.ts:323) for the engine's lock wait and
18
+ * its stand-down; dropping it for these hooks is sql-yodeler#293's.
19
+ */
20
+ import type { LockGrain } from "@intentius/chant/lifecycle/lock-rows";
21
+ /** The capability kinds this lexicon gives a grain to. */
22
+ export type SqlLockGrainKind = "sql-migrate" | "sql-apply";
23
+ /** The grain a SQL member takes when `ci.lockGrain` sets none: always `target`. */
24
+ export declare function sqlDefaultLockGrain(): LockGrain;
25
+ /** Why a SQL member cannot take `grain`, naming the engine; undefined for `target` and `repo`. */
26
+ export declare function sqlLockGrainRefusal(kind: SqlLockGrainKind, grain: LockGrain): string | undefined;
27
+ //# sourceMappingURL=lock-grain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lock-grain.d.ts","sourceRoot":"","sources":["../src/lock-grain.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAEtE,0DAA0D;AAC1D,MAAM,MAAM,gBAAgB,GAAG,aAAa,GAAG,WAAW,CAAC;AAE3D,mFAAmF;AACnF,wBAAgB,mBAAmB,IAAI,SAAS,CAE/C;AAED,kGAAkG;AAClG,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,EAAE,SAAS,GAAG,MAAM,GAAG,SAAS,CAMhG"}
@@ -0,0 +1,13 @@
1
+ /** The grain a SQL member takes when `ci.lockGrain` sets none: always `target`. */
2
+ export function sqlDefaultLockGrain() {
3
+ return "target";
4
+ }
5
+ /** Why a SQL member cannot take `grain`, naming the engine; undefined for `target` and `repo`. */
6
+ export function sqlLockGrainRefusal(kind, grain) {
7
+ if (grain !== "resource")
8
+ return undefined;
9
+ if (kind === "sql-migrate") {
10
+ return "SQL Yodeler applies an environment's migrations in chain order under the environment's own lock (a KeeperMap row on ClickHouse, a session advisory lock on Postgres), so nothing in it is per resource (ci.lockGrain: target)";
11
+ }
12
+ return "the sql lexicon's applier sends a whole build in creation order, since its objects depend on each other, so nothing in it is per resource (ci.lockGrain: target)";
13
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sql",
3
- "version": "0.124.54",
3
+ "version": "0.124.55",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "SQL",
6
6
  "intrinsics": [],
@@ -1 +1 @@
1
- {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA0B5E,eAAO,MAAM,SAAS,EAAE,aA+SvB,CAAC"}
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAgB,aAAa,EAAE,MAAM,0BAA0B,CAAC;AA2B5E,eAAO,MAAM,SAAS,EAAE,aAuTvB,CAAC"}
package/dist/plugin.js CHANGED
@@ -30,6 +30,7 @@ import { looksLikePostgres } from "./migrate/from-postgres/detect.js";
30
30
  import { sqlWorkspaceOutputs } from "./workspace-outputs.js";
31
31
  import { CDC_TEMPLATE, DEFAULT_TEMPLATE, EVENTS_TEMPLATE, POSTGRES_EVENTS_TEMPLATE, POSTGRES_TEMPLATE, POSTGRES_TENANT_TEMPLATE } from "./init-templates.js";
32
32
  import { compositeCatalog } from "./composites/catalog.js";
33
+ import { sqlCiServices, sqlCiSetup } from "./ci-setup.js";
33
34
  export const sqlPlugin = {
34
35
  name: "sql",
35
36
  serializer: sqlSerializer,
@@ -38,6 +39,13 @@ export const sqlPlugin = {
38
39
  emulator: [CLICKHOUSE_EMULATOR, POSTGRES_EMULATOR],
39
40
  /** chant's marker is a trailer on the object's comment (#3208, ./clickhouse/ownership.ts). */
40
41
  ownershipChannel: SQL_OWNERSHIP_CHANNEL,
42
+ // #4572: the setup lines for the pull request pipeline's default image, and the replay server per dialect.
43
+ ciSetup(ctx) {
44
+ return sqlCiSetup(ctx);
45
+ },
46
+ ciServices(ctx) {
47
+ return sqlCiServices(ctx);
48
+ },
41
49
  async generate(options) {
42
50
  const { generate, writeGeneratedFiles } = await import("./codegen/generate.js");
43
51
  writeGeneratedFiles(await generate(options));
@@ -18,6 +18,8 @@ export declare class ApprovingLedger {
18
18
  appended: import("@intentius/chant/point-decision").PendingGateRecord[];
19
19
  resolved: import("@intentius/chant/point-decision").GateResolutionRecord[];
20
20
  applied: import("@intentius/chant/gate-decision").AppliedGateRecord[];
21
+ finished: import("@intentius/chant/lifecycle/gate-applied").FinishedGateRecord[];
22
+ attachments: Map<string, string>;
21
23
  checkpoints: Map<string, string>;
22
24
  };
23
25
  approveLast(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../../src/postgres/testing/migration.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAoD,KAAK,UAAU,EAAE,KAAK,cAAc,EAAiB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE9J,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAEpF,gGAAgG;AAChG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,qBAAqB,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAO/F;AAED,gFAAgF;AAChF,wBAAsB,cAAc,CAAC,MAAM,EAAE,yBAAyB,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAItJ;AAED,uIAAuI;AACvI,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAAiB;IACpC,IAAI;;;;;MAA0B;IAE9B,WAAW,IAAI,IAAI;CAcpB;AAED,2CAA2C;AAC3C,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,EAAE,MAAM,MAAM,KAAG,OAAyF,CAAC"}
1
+ {"version":3,"file":"migration.d.ts","sourceRoot":"","sources":["../../../src/postgres/testing/migration.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAoD,KAAK,UAAU,EAAE,KAAK,cAAc,EAAiB,KAAK,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE9J,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AACpF,OAAO,EAAuB,KAAK,yBAAyB,EAAE,MAAM,eAAe,CAAC;AAEpF,gGAAgG;AAChG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,qBAAqB,GAAG,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAO/F;AAED,gFAAgF;AAChF,wBAAsB,cAAc,CAAC,MAAM,EAAE,yBAAyB,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,EAAE,MAAM,qBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAItJ;AAED,uIAAuI;AACvI,qBAAa,eAAe;IAC1B,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,WAAW,CAAiB;IACpC,IAAI;;;;;;;MAA0B;IAE9B,WAAW,IAAI,IAAI;CAcpB;AAED,2CAA2C;AAC3C,eAAO,MAAM,UAAU,GAAI,GAAG,WAAW,EAAE,MAAM,MAAM,KAAG,OAAyF,CAAC"}
@@ -21,6 +21,22 @@
21
21
  * - `entra`: `az account get-access-token` for Azure Database for PostgreSQL.
22
22
  * - `command`: any command that prints a password on its standard output.
23
23
  *
24
+ * In a CI job that traded its OIDC token through chant's `ci.identity`
25
+ * (`@intentius/chant/ci-identity`, #4296, #4572), the cloud sources mint
26
+ * from what the trade left instead, with no cloud command line in the
27
+ * image ({@link tradedToken}):
28
+ *
29
+ * - `rds-iam` presigns the token with the traded AWS keys
30
+ * (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`),
31
+ * through chant's SigV4 signer, as `aws rds generate-db-auth-token` does.
32
+ * - `cloud-sql-iam` is the traded Google access token
33
+ * (`GOOGLE_OAUTH_ACCESS_TOKEN`), which Cloud SQL's IAM sign-in takes.
34
+ * - `entra` is `AZURE_DATABASE_ACCESS_TOKEN`, which the trade sets with
35
+ * `ci.identity.cloud.azure.database`. The ARM token it always sets is
36
+ * for another scope, so without `database` `entra` still runs `az`.
37
+ *
38
+ * Outside CI none of these variables is set and the command lines run.
39
+ *
24
40
  * A token is reused until most of its lifetime has passed and minted again
25
41
  * after, so a long apply, whose ClickHouse requests each carry the password
26
42
  * and whose Postgres connections each authenticate when opened, never sends
@@ -67,6 +83,18 @@ export interface CredentialSource {
67
83
  /** Forget the cached token, so the next `get()` mints again. */
68
84
  invalidate(): void;
69
85
  }
86
+ /** The variable chant's trade sets to an Azure Database for PostgreSQL token (`AZURE_DATABASE_TOKEN_ENV` in `@intentius/chant/ci-identity`, #4572). */
87
+ export declare const AZURE_DATABASE_TOKEN_ENV = "AZURE_DATABASE_ACCESS_TOKEN";
88
+ /**
89
+ * The token a cloud source takes from chant's traded identity (#4572), when
90
+ * the job's environment holds it; undefined otherwise, and for `command`.
91
+ * Pure but for `now`, for tests.
92
+ */
93
+ export declare function tradedToken(config: TokenSourceConfig, input: {
94
+ url: string;
95
+ user?: string;
96
+ env: Record<string, string | undefined>;
97
+ }, now?: Date): string | undefined;
70
98
  /** The program a source runs. Pure, for tests. */
71
99
  export declare function tokenCommand(config: TokenSourceConfig, input: {
72
100
  url: string;
@@ -1 +1 @@
1
- {"version":3,"file":"token-source.d.ts","sourceRoot":"","sources":["../src/token-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,yDAAyD;AACzD,eAAO,MAAM,iBAAiB;;IAG1B,kGAAkG;;IAElG,kFAAkF;;;;IAKlF,gEAAgE;;;;IAKhE,gEAAgE;;;;IAKhE,yGAAyG;;IAEzG,+DAA+D;;6BAGjE,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,gEAAgE;AAChE,eAAO,MAAM,2BAA2B,EAAE,WAAW,CAAC,MAAM,CAAkD,CAAC;AAY/G,+GAA+G;AAC/G,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,sEAAsE;AACtE,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAU/G,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACvB,gEAAgE;IAChE,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,kDAAkD;AAClD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,GAC7E,SAAS,MAAM,EAAE,CA0BnB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IACL,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,GACA,gBAAgB,CAoClB"}
1
+ {"version":3,"file":"token-source.d.ts","sourceRoot":"","sources":["../src/token-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,yDAAyD;AACzD,eAAO,MAAM,iBAAiB;;IAG1B,kGAAkG;;IAElG,kFAAkF;;;;IAKlF,gEAAgE;;;;IAKhE,gEAAgE;;;;IAKhE,yGAAyG;;IAEzG,+DAA+D;;6BAGjE,CAAC;AAEH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAElE,gEAAgE;AAChE,eAAO,MAAM,2BAA2B,EAAE,WAAW,CAAC,MAAM,CAAkD,CAAC;AAY/G,+GAA+G;AAC/G,qBAAa,gBAAiB,SAAQ,KAAK;gBAC7B,OAAO,EAAE,MAAM;CAI5B;AAED,sEAAsE;AACtE,MAAM,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;AAU/G,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,0FAA0F;IAC1F,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACvB,gEAAgE;IAChE,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,uJAAuJ;AACvJ,eAAO,MAAM,wBAAwB,gCAAgC,CAAC;AAOtE;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,EAC9E,GAAG,GAAE,IAAiB,GACrB,MAAM,GAAG,SAAS,CA+BpB;AAED,kDAAkD;AAClD,wBAAgB,YAAY,CAC1B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAA;CAAE,GAC7E,SAAS,MAAM,EAAE,CA0BnB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EACzB,KAAK,EAAE;IACL,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,UAAU,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,GACA,gBAAgB,CA0ClB"}
@@ -21,6 +21,22 @@
21
21
  * - `entra`: `az account get-access-token` for Azure Database for PostgreSQL.
22
22
  * - `command`: any command that prints a password on its standard output.
23
23
  *
24
+ * In a CI job that traded its OIDC token through chant's `ci.identity`
25
+ * (`@intentius/chant/ci-identity`, #4296, #4572), the cloud sources mint
26
+ * from what the trade left instead, with no cloud command line in the
27
+ * image ({@link tradedToken}):
28
+ *
29
+ * - `rds-iam` presigns the token with the traded AWS keys
30
+ * (`AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`),
31
+ * through chant's SigV4 signer, as `aws rds generate-db-auth-token` does.
32
+ * - `cloud-sql-iam` is the traded Google access token
33
+ * (`GOOGLE_OAUTH_ACCESS_TOKEN`), which Cloud SQL's IAM sign-in takes.
34
+ * - `entra` is `AZURE_DATABASE_ACCESS_TOKEN`, which the trade sets with
35
+ * `ci.identity.cloud.azure.database`. The ARM token it always sets is
36
+ * for another scope, so without `database` `entra` still runs `az`.
37
+ *
38
+ * Outside CI none of these variables is set and the command lines run.
39
+ *
24
40
  * A token is reused until most of its lifetime has passed and minted again
25
41
  * after, so a long apply, whose ClickHouse requests each carry the password
26
42
  * and whose Postgres connections each authenticate when opened, never sends
@@ -28,6 +44,7 @@
28
44
  */
29
45
  import { execFile } from "node:child_process";
30
46
  import { z } from "zod";
47
+ import { presignV4 } from "@intentius/chant/cloud-lister/sigv4";
31
48
  const ttl = z.number().int().positive().optional();
32
49
  /** The token sources a profile's `password` can name. */
33
50
  export const tokenSourceSchema = z.discriminatedUnion("token", [
@@ -81,6 +98,52 @@ const runCommand = (argv, env) => new Promise((resolve, reject) => {
81
98
  resolve(String(stdout));
82
99
  });
83
100
  });
101
+ /** The variable chant's trade sets to an Azure Database for PostgreSQL token (`AZURE_DATABASE_TOKEN_ENV` in `@intentius/chant/ci-identity`, #4572). */
102
+ export const AZURE_DATABASE_TOKEN_ENV = "AZURE_DATABASE_ACCESS_TOKEN";
103
+ /** The region an `rds-iam` token is signed for: the config's, `AWS_REGION`, `AWS_DEFAULT_REGION`, else the RDS host name's. */
104
+ function rdsRegion(config, hostname, env) {
105
+ return config.region ?? env.AWS_REGION ?? env.AWS_DEFAULT_REGION ?? /\.([a-z]{2}(?:-[a-z]+)+-\d+)\.rds\.amazonaws\.com$/.exec(hostname)?.[1];
106
+ }
107
+ /**
108
+ * The token a cloud source takes from chant's traded identity (#4572), when
109
+ * the job's environment holds it; undefined otherwise, and for `command`.
110
+ * Pure but for `now`, for tests.
111
+ */
112
+ export function tradedToken(config, input, now = new Date()) {
113
+ const env = input.env;
114
+ switch (config.token) {
115
+ case "command":
116
+ return undefined;
117
+ case "cloud-sql-iam":
118
+ return env.GOOGLE_OAUTH_ACCESS_TOKEN || env.CLOUDSDK_AUTH_ACCESS_TOKEN || undefined;
119
+ case "entra":
120
+ return env[AZURE_DATABASE_TOKEN_ENV] || undefined;
121
+ case "rds-iam": {
122
+ const accessKeyId = env.AWS_ACCESS_KEY_ID;
123
+ const secretAccessKey = env.AWS_SECRET_ACCESS_KEY;
124
+ if (!accessKeyId || !secretAccessKey)
125
+ return undefined;
126
+ if (input.user === undefined)
127
+ throw new TokenSourceError("rds-iam mints a token for one database user; the profile names no user");
128
+ const url = new URL(input.url);
129
+ const region = rdsRegion(config, url.hostname, env);
130
+ if (region === undefined)
131
+ throw new TokenSourceError(`rds-iam signs its token for a region; set the token source's region or AWS_REGION for ${url.hostname}`);
132
+ const target = new URL(`https://${url.hostname}:${url.port || "5432"}/`);
133
+ target.searchParams.set("Action", "connect");
134
+ target.searchParams.set("DBUser", input.user);
135
+ const signed = presignV4({
136
+ url: target.toString(),
137
+ region,
138
+ service: "rds-db",
139
+ credentials: { accessKeyId, secretAccessKey, ...(env.AWS_SESSION_TOKEN ? { sessionToken: env.AWS_SESSION_TOKEN } : {}) },
140
+ seconds: DEFAULT_TTL_SECONDS["rds-iam"],
141
+ now,
142
+ });
143
+ return signed.replace(/^https:\/\//, "");
144
+ }
145
+ }
146
+ }
84
147
  /** The program a source runs. Pure, for tests. */
85
148
  export function tokenCommand(config, input) {
86
149
  switch (config.token) {
@@ -94,7 +157,7 @@ export function tokenCommand(config, input) {
94
157
  const url = new URL(input.url);
95
158
  if (input.user === undefined)
96
159
  throw new TokenSourceError("rds-iam mints a token for one database user; the profile names no user");
97
- const region = config.region ?? input.env.AWS_REGION ?? input.env.AWS_DEFAULT_REGION ?? /\.([a-z]{2}(?:-[a-z]+)+-\d+)\.rds\.amazonaws\.com$/.exec(url.hostname)?.[1];
160
+ const region = rdsRegion(config, url.hostname, input.env);
98
161
  return [
99
162
  "aws",
100
163
  "rds",
@@ -122,6 +185,12 @@ export function credentialSource(config, input) {
122
185
  let cached;
123
186
  let pending;
124
187
  const mint = async () => {
188
+ // #4572: a CI job that traded its OIDC token through chant mints from what the trade left.
189
+ const traded = tradedToken(config, input, new Date(now()));
190
+ if (traded !== undefined) {
191
+ cached = { token: traded, until: now() + lifetimeMs };
192
+ return traded;
193
+ }
125
194
  const argv = tokenCommand(config, input);
126
195
  let out;
127
196
  try {
@@ -0,0 +1,58 @@
1
+ /** What one yodel run gave. Never thrown: a non-zero exit is a `code`. */
2
+ export interface YodelRun {
3
+ /** The exit status; null when the process did not exit by itself or never started. */
4
+ code: number | null;
5
+ stdout: string;
6
+ stderr: string;
7
+ /** No yodel binary was found. */
8
+ missingBinary?: boolean;
9
+ }
10
+ /** Runs yodel with these arguments in `cwd`, with `env`. Injectable so tests need no binary. */
11
+ export type YodelRunner = (args: string[], opts: {
12
+ cwd: string;
13
+ env: NodeJS.ProcessEnv;
14
+ dir?: string;
15
+ }) => Promise<YodelRun>;
16
+ /**
17
+ * The only yodel commands chant runs (ruling A on sql-yodeler#285). Each
18
+ * may be followed by `--dir <project>`, `--op <name>` and
19
+ * `--allow-out-of-order`, in that order ({@link YODEL_OPTIONAL_FLAGS}).
20
+ */
21
+ export declare const YODEL_COMMANDS: readonly string[];
22
+ /** The flags any of {@link YODEL_COMMANDS} may end with, in this order. */
23
+ export declare const YODEL_OPTIONAL_FLAGS: readonly string[];
24
+ /** The options every command takes. */
25
+ export interface YodelCommonOptions {
26
+ /** The yodel project directory, passed as `--dir`. */
27
+ dir?: string;
28
+ /** The migrations Op, when more than one applies the environment. */
29
+ op?: string;
30
+ allowOutOfOrder?: boolean;
31
+ }
32
+ /** `yodel plan <env> --part <file>`, without the binary. */
33
+ export declare function yodelPlanArgs(env: string, part: string, opts?: YodelCommonOptions): string[];
34
+ /** `yodel apply <env> --wave-plan <file> --spec <spec>`, without the binary. */
35
+ export declare function yodelWavePlanArgs(env: string, file: string, spec: string, opts?: YodelCommonOptions): string[];
36
+ /** `yodel apply <env> --wave-apply <file> --spec <spec>`, without the binary. */
37
+ export declare function yodelWaveApplyArgs(env: string, file: string, spec: string, opts?: YodelCommonOptions): string[];
38
+ /** Whether `args` is one of {@link YODEL_COMMANDS} with an allowed tail. */
39
+ export declare function allowedYodelArgv(args: readonly string[]): boolean;
40
+ /** Whether `args` is the apply, the one command that writes. */
41
+ export declare function isYodelApplyArgv(args: readonly string[]): boolean;
42
+ /** Run `args` through `run`, refusing any argv off {@link YODEL_COMMANDS}. */
43
+ export declare function runAllowedYodel(run: YodelRunner, args: string[], opts: {
44
+ cwd: string;
45
+ env: NodeJS.ProcessEnv;
46
+ dir?: string;
47
+ }): Promise<YodelRun>;
48
+ /** The variables that pick the writer (sql-yodeler `credentials.ts`). */
49
+ export declare const YODEL_ROLE_VARIABLES: readonly string[];
50
+ /** `env` with the writer taken out: what the planning commands run with. */
51
+ export declare function readerEnv(env?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
52
+ /**
53
+ * The yodel binary: the project's `node_modules/.bin/yodel`, else the
54
+ * working directory's, else `yodel` on PATH. Always a file named `yodel`.
55
+ */
56
+ export declare function yodelBinary(cwd: string, dir?: string): string;
57
+ export declare const defaultYodelRunner: YodelRunner;
58
+ //# sourceMappingURL=yodel-run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"yodel-run.d.ts","sourceRoot":"","sources":["../src/yodel-run.ts"],"names":[],"mappings":"AA0CA,0EAA0E;AAC1E,MAAM,WAAW,QAAQ;IACvB,sFAAsF;IACtF,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,iCAAiC;IACjC,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,gGAAgG;AAChG,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE7H;;;;GAIG;AACH,eAAO,MAAM,cAAc,EAAE,SAAS,MAAM,EAI3C,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAA+D,CAAC;AAElH,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD,4DAA4D;AAC5D,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,MAAM,EAAE,CAEhG;AAED,gFAAgF;AAChF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,MAAM,EAAE,CAElH;AAED,iFAAiF;AACjF,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,kBAAuB,GAAG,MAAM,EAAE,CAEnH;AAoBD,4EAA4E;AAC5E,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAOjE;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAEjE;AAED,8EAA8E;AAC9E,wBAAsB,eAAe,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAKtJ;AAED,yEAAyE;AACzE,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAAwC,CAAC;AAK3F,4EAA4E;AAC5E,wBAAgB,SAAS,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,CAAC,UAAU,CAOjF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAM7D;AAED,eAAO,MAAM,kBAAkB,EAAE,WAQ7B,CAAC"}