typekro 0.34.0 → 0.36.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.
Files changed (90) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/alchemy/clickhouse-schema/executor.d.ts +25 -0
  3. package/dist/alchemy/clickhouse-schema/executor.d.ts.map +1 -0
  4. package/dist/alchemy/clickhouse-schema/executor.js +144 -0
  5. package/dist/alchemy/clickhouse-schema/executor.js.map +1 -0
  6. package/dist/alchemy/clickhouse-schema/index.d.ts +12 -0
  7. package/dist/alchemy/clickhouse-schema/index.d.ts.map +1 -0
  8. package/dist/alchemy/clickhouse-schema/index.js +11 -0
  9. package/dist/alchemy/clickhouse-schema/index.js.map +1 -0
  10. package/dist/alchemy/clickhouse-schema/resource.d.ts +54 -0
  11. package/dist/alchemy/clickhouse-schema/resource.d.ts.map +1 -0
  12. package/dist/alchemy/clickhouse-schema/resource.js +158 -0
  13. package/dist/alchemy/clickhouse-schema/resource.js.map +1 -0
  14. package/dist/alchemy/clickhouse-schema/runner.d.ts +154 -0
  15. package/dist/alchemy/clickhouse-schema/runner.d.ts.map +1 -0
  16. package/dist/alchemy/clickhouse-schema/runner.js +613 -0
  17. package/dist/alchemy/clickhouse-schema/runner.js.map +1 -0
  18. package/dist/alchemy/clickhouse-schema/sql.d.ts +109 -0
  19. package/dist/alchemy/clickhouse-schema/sql.d.ts.map +1 -0
  20. package/dist/alchemy/clickhouse-schema/sql.js +368 -0
  21. package/dist/alchemy/clickhouse-schema/sql.js.map +1 -0
  22. package/dist/alchemy/clickhouse-schema/types.d.ts +394 -0
  23. package/dist/alchemy/clickhouse-schema/types.d.ts.map +1 -0
  24. package/dist/alchemy/clickhouse-schema/types.js +370 -0
  25. package/dist/alchemy/clickhouse-schema/types.js.map +1 -0
  26. package/dist/alchemy/index.d.ts +1 -0
  27. package/dist/alchemy/index.d.ts.map +1 -1
  28. package/dist/alchemy/index.js +2 -0
  29. package/dist/alchemy/index.js.map +1 -1
  30. package/dist/alchemy/kro-delete.d.ts +7 -0
  31. package/dist/alchemy/kro-delete.d.ts.map +1 -1
  32. package/dist/alchemy/kro-delete.js +28 -4
  33. package/dist/alchemy/kro-delete.js.map +1 -1
  34. package/dist/alchemy/resource-registration.d.ts +9 -2
  35. package/dist/alchemy/resource-registration.d.ts.map +1 -1
  36. package/dist/alchemy/resource-registration.js +117 -33
  37. package/dist/alchemy/resource-registration.js.map +1 -1
  38. package/dist/core/deployment/k8s-helpers.d.ts +77 -1
  39. package/dist/core/deployment/k8s-helpers.d.ts.map +1 -1
  40. package/dist/core/deployment/k8s-helpers.js +298 -17
  41. package/dist/core/deployment/k8s-helpers.js.map +1 -1
  42. package/dist/core/deployment/kro-artifact-binding-migration.d.ts +17 -6
  43. package/dist/core/deployment/kro-artifact-binding-migration.d.ts.map +1 -1
  44. package/dist/core/deployment/kro-artifact-binding-migration.js +16 -2
  45. package/dist/core/deployment/kro-artifact-binding-migration.js.map +1 -1
  46. package/dist/core/deployment/kro-namespace-teardown.d.ts +15 -1
  47. package/dist/core/deployment/kro-namespace-teardown.d.ts.map +1 -1
  48. package/dist/core/deployment/kro-namespace-teardown.js +34 -9
  49. package/dist/core/deployment/kro-namespace-teardown.js.map +1 -1
  50. package/dist/core/deployment/kro-readiness.d.ts +35 -0
  51. package/dist/core/deployment/kro-readiness.d.ts.map +1 -1
  52. package/dist/core/deployment/kro-readiness.js +201 -25
  53. package/dist/core/deployment/kro-readiness.js.map +1 -1
  54. package/dist/core/deployment/poll-timeout.d.ts +80 -2
  55. package/dist/core/deployment/poll-timeout.d.ts.map +1 -1
  56. package/dist/core/deployment/poll-timeout.js +164 -4
  57. package/dist/core/deployment/poll-timeout.js.map +1 -1
  58. package/dist/core/kubernetes/bun-http-library.d.ts +24 -0
  59. package/dist/core/kubernetes/bun-http-library.d.ts.map +1 -1
  60. package/dist/core/kubernetes/bun-http-library.js +146 -19
  61. package/dist/core/kubernetes/bun-http-library.js.map +1 -1
  62. package/dist/core/kubernetes/errors.d.ts +9 -0
  63. package/dist/core/kubernetes/errors.d.ts.map +1 -1
  64. package/dist/core/kubernetes/errors.js +7 -3
  65. package/dist/core/kubernetes/errors.js.map +1 -1
  66. package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts +24 -2
  67. package/dist/factories/clickhouse/compositions/clickhouse-cluster.d.ts.map +1 -1
  68. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js +24 -2
  69. package/dist/factories/clickhouse/compositions/clickhouse-cluster.js.map +1 -1
  70. package/dist/factories/clickhouse/resources/keeper.d.ts +61 -0
  71. package/dist/factories/clickhouse/resources/keeper.d.ts.map +1 -1
  72. package/dist/factories/clickhouse/resources/keeper.js +216 -2
  73. package/dist/factories/clickhouse/resources/keeper.js.map +1 -1
  74. package/dist/factories/clickhouse/resources/s3-backup.d.ts.map +1 -1
  75. package/dist/factories/clickhouse/resources/s3-backup.js +4 -3
  76. package/dist/factories/clickhouse/resources/s3-backup.js.map +1 -1
  77. package/dist/factories/clickhouse/types.d.ts +3 -2
  78. package/dist/factories/clickhouse/types.d.ts.map +1 -1
  79. package/dist/factories/clickhouse/types.js +28 -1
  80. package/dist/factories/clickhouse/types.js.map +1 -1
  81. package/dist/factories/clickhouse/utils/validation.d.ts +133 -10
  82. package/dist/factories/clickhouse/utils/validation.d.ts.map +1 -1
  83. package/dist/factories/clickhouse/utils/validation.js +165 -18
  84. package/dist/factories/clickhouse/utils/validation.js.map +1 -1
  85. package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts +15 -1
  86. package/dist/factories/clickstack/compositions/clickstack-bootstrap.d.ts.map +1 -1
  87. package/dist/factories/clickstack/compositions/clickstack-bootstrap.js +15 -1
  88. package/dist/factories/clickstack/compositions/clickstack-bootstrap.js.map +1 -1
  89. package/dist/factories/rook/types.d.ts +16 -16
  90. package/package.json +1 -1
@@ -0,0 +1,109 @@
1
+ /**
2
+ * ClickHouse SQL text analysis: a small lexer plus the two things that read it.
3
+ *
4
+ * TypeKro never REWRITES a statement — an author's DDL reaches the server byte for byte.
5
+ * It does have to READ statements for two reasons, and both need the same thing: a scan
6
+ * that knows where a string literal starts and ends.
7
+ *
8
+ * 1. {@link validateOnClusterStatement} decides whether a statement is actually
9
+ * cluster-wide, so `execution.mode: 'onCluster'` can reject a statement that would
10
+ * silently land on one replica instead of rewriting it into something it wasn't.
11
+ * 2. {@link extractStatementSecrets} collects the literals a statement contains, so the
12
+ * server's own error text — which quotes the offending fragment back — can be redacted
13
+ * against what was actually submitted rather than against a keyword list that a
14
+ * positional `S3('…','AKIA…','wJalr…','CSV')` walks straight past.
15
+ *
16
+ * Deliberately not a SQL parser. It resolves quoting and comments and nothing else; every
17
+ * question above is answered conservatively, so an unrecognised shape is rejected (1) or
18
+ * over-redacted (2) rather than waved through.
19
+ */
20
+ /** One lexical unit. Numbers and operators collapse into `punct` — nothing here reads them. */
21
+ export type ClickHouseSqlToken = {
22
+ readonly kind: 'word';
23
+ readonly value: string;
24
+ } | {
25
+ readonly kind: 'quoted';
26
+ /** The DECODED value — what the server actually receives. */
27
+ readonly value: string;
28
+ /**
29
+ * The SOURCE slice between the quotes, escapes intact.
30
+ *
31
+ * Kept alongside the decoded value because ClickHouse echoes a bad fragment back in
32
+ * whichever spelling it feels like, and `pa\'ss` and `pa''ss` are the same secret as
33
+ * `pa'ss`. Redaction has to blank all of them; see {@link extractStatementSecrets}.
34
+ */
35
+ readonly raw: string;
36
+ readonly quote: "'" | '"' | '`';
37
+ } | {
38
+ readonly kind: 'punct';
39
+ readonly value: string;
40
+ };
41
+ /**
42
+ * The C-style SOURCE spelling of a decoded value, inverting {@link CLICKHOUSE_ESCAPES}.
43
+ *
44
+ * `decode(escapeClickHouseString(value)) === value` for every value, which is the property
45
+ * redaction needs: a secret's raw and decoded spellings have to be two views of one string,
46
+ * or one of them survives into an error message.
47
+ */
48
+ export declare function escapeClickHouseString(value: string): string;
49
+ /**
50
+ * Split a statement into words, quoted values and single punctuation characters.
51
+ *
52
+ * Comments (`--`, `#`, `/* … *\/`) are dropped. Quoted values are returned DECODED — the
53
+ * doubling and backslash escapes ClickHouse accepts are resolved — because both callers
54
+ * compare against the value the server sees. The SOURCE slice is returned as well, because
55
+ * the server may echo back either spelling.
56
+ */
57
+ export declare function tokenizeClickHouseSql(statement: string): readonly ClickHouseSqlToken[];
58
+ /**
59
+ * Whether the statement carries `ON CLUSTER <cluster>` naming exactly this cluster.
60
+ *
61
+ * Case-insensitive in the keywords, exact in the cluster name, and indifferent to how
62
+ * the name is spelled — bare, backtick-quoted, double-quoted or single-quoted are all the
63
+ * same identifier to ClickHouse. A match inside a string literal cannot be mistaken for
64
+ * the real clause because the lexer has already resolved literals into `quoted` tokens.
65
+ */
66
+ export declare function statementTargetsCluster(statement: string, cluster: string): boolean;
67
+ /**
68
+ * The leading keyword, lowercased — `undefined` for a statement that starts with anything
69
+ * other than a bare word.
70
+ */
71
+ export declare function leadingKeyword(statement: string): string | undefined;
72
+ /**
73
+ * Prove that a statement applies to every server, under `execution.mode: 'onCluster'`.
74
+ *
75
+ * EXACTLY ONE proof is accepted: the statement carries `ON CLUSTER <cluster>`, naming the
76
+ * configured cluster, so the initiating server distributes it through Keeper's DDL queue.
77
+ *
78
+ * Nothing is INFERRED from the statement's shape. An earlier version accepted a clause-free
79
+ * statement whose dotted references were all on a `replicatedDatabases` allow-list, which
80
+ * keyed on the references rather than on the DDL TARGET: `CREATE TABLE events AS
81
+ * analytics.source` passed the check while creating `events` on one server only. Deciding
82
+ * this properly means parsing the target of every DDL form ClickHouse accepts, and a
83
+ * parser that is subtly wrong here silently half-applies a schema — so the safe rule is
84
+ * the explicit one, and the author writes the clause.
85
+ *
86
+ * The statement is never rewritten. Adding `ON CLUSTER` on the author's behalf would
87
+ * change the semantics of DDL TypeKro did not write, and getting that wrong on a
88
+ * production cluster is not recoverable.
89
+ *
90
+ * Statements that legitimately cannot carry the clause — `SET`, `USE`, a single-node
91
+ * `SYSTEM …`, `INSERT` — do not belong under `onCluster` at all; `fanout` runs them on
92
+ * every server itself, and reaching every server is then the author's business.
93
+ */
94
+ export declare function validateOnClusterStatement(statement: string, cluster: string): string | undefined;
95
+ /**
96
+ * Every value in the SUBMITTED statement that must not survive into a captured message,
97
+ * in every spelling it could be echoed in, LONGEST FIRST.
98
+ *
99
+ * Deliberately over-broad: EVERY single-quoted literal counts, not only the ones a
100
+ * keyword introduces. That is the whole point — the case keyword matching misses is the
101
+ * positional one, `S3('https://…', '<key id>', '<secret>', 'CSV')`, where nothing in the
102
+ * text says which argument is the credential. Redacting a harmless literal costs a word
103
+ * of an error message; leaking the other kind costs the key.
104
+ *
105
+ * Longest first so that replacing one form cannot leave a shorter form of the same secret
106
+ * stranded inside what is left of a longer one.
107
+ */
108
+ export declare function extractStatementSecrets(statement: string): readonly string[];
109
+ //# sourceMappingURL=sql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../../src/alchemy/clickhouse-schema/sql.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,+FAA+F;AAC/F,MAAM,MAAM,kBAAkB,GAC1B;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjD;IACE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,KAAK,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;CACjC,GACD;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AA4FvD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM5D;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,kBAAkB,EAAE,CAuEtF;AAcD;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAOnF;AAKD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGpE;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,0BAA0B,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAgBjG;AAqDD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAwC5E"}
@@ -0,0 +1,368 @@
1
+ /**
2
+ * ClickHouse SQL text analysis: a small lexer plus the two things that read it.
3
+ *
4
+ * TypeKro never REWRITES a statement — an author's DDL reaches the server byte for byte.
5
+ * It does have to READ statements for two reasons, and both need the same thing: a scan
6
+ * that knows where a string literal starts and ends.
7
+ *
8
+ * 1. {@link validateOnClusterStatement} decides whether a statement is actually
9
+ * cluster-wide, so `execution.mode: 'onCluster'` can reject a statement that would
10
+ * silently land on one replica instead of rewriting it into something it wasn't.
11
+ * 2. {@link extractStatementSecrets} collects the literals a statement contains, so the
12
+ * server's own error text — which quotes the offending fragment back — can be redacted
13
+ * against what was actually submitted rather than against a keyword list that a
14
+ * positional `S3('…','AKIA…','wJalr…','CSV')` walks straight past.
15
+ *
16
+ * Deliberately not a SQL parser. It resolves quoting and comments and nothing else; every
17
+ * question above is answered conservatively, so an unrecognised shape is rejected (1) or
18
+ * over-redacted (2) rather than waved through.
19
+ */
20
+ const WORD_START = /[A-Za-z_]/;
21
+ const WORD_BODY = /[A-Za-z0-9_$]/;
22
+ /**
23
+ * ClickHouse's C-style escape table — the SINGLE source of truth for both directions.
24
+ *
25
+ * Reading it wrong is a redaction hole, not a cosmetic bug: a decoder that turns every
26
+ * `\c` into `c` decodes `\n` to the letter `n`, so a credential whose value contains a
27
+ * newline is extracted in a spelling the server never emits, and the real decoded form
28
+ * survives into the retained error text. Both directions therefore come from this one
29
+ * table: {@link decodeEscape} reads it, {@link escapeClickHouseString} inverts it, and a
30
+ * raw source spelling and its decoded value round-trip.
31
+ *
32
+ * Each entry is `[<character after the backslash>, <what the server decodes it to>]`, per
33
+ * https://clickhouse.com/docs/sql-reference/syntax#string. Handled outside the table
34
+ * because neither is a single character mapping: `\xHH` (a byte, see {@link decodeEscape})
35
+ * and `\N` (documented as "reserved, does nothing" — `SELECT 'a\Nb'` returns `ab`, so it
36
+ * decodes to the empty string).
37
+ *
38
+ * @see https://clickhouse.com/docs/sql-reference/syntax#string
39
+ */
40
+ const CLICKHOUSE_ESCAPES = [
41
+ ['a', '\x07'], // alert
42
+ ['b', '\b'], // backspace
43
+ ['e', '\x1b'], // escape character
44
+ ['f', '\f'], // form feed
45
+ ['n', '\n'], // line feed
46
+ ['r', '\r'], // carriage return
47
+ ['t', '\t'], // horizontal tab
48
+ ['v', '\v'], // vertical tab
49
+ ['0', '\0'], // null character
50
+ ['\\', '\\'],
51
+ ["'", "'"], // `''` is the other spelling, resolved by the tokenizer's doubling branch
52
+ ['"', '"'],
53
+ ['`', '`'],
54
+ ['/', '/'],
55
+ ['=', '='],
56
+ ];
57
+ const ESCAPE_DECODE = new Map(CLICKHOUSE_ESCAPES);
58
+ /**
59
+ * The inverse table, restricted to the characters a single-quoted literal cannot carry
60
+ * verbatim: the backslash, the single quote, and the control characters the table names
61
+ * (every one of them is `<= 31`, which is how ClickHouse itself decides to drop the
62
+ * backslash). A `"`, a backtick, a `/` or an `=` needs no escape inside `'…'`, so the
63
+ * source spelling ClickHouse would echo for those is the character itself.
64
+ */
65
+ const ESCAPE_ENCODE = new Map(CLICKHOUSE_ESCAPES.filter(([, decoded]) => decoded === '\\' || decoded === "'" || decoded <= '\x1f').map(([escape, decoded]) => [decoded, `\\${escape}`]));
66
+ const HEX_PAIR = /^[0-9A-Fa-f]{2}$/;
67
+ /**
68
+ * Decode the one backslash escape starting at `index` (which points AT the backslash).
69
+ *
70
+ * Returns the decoded text and how many SOURCE characters it consumed, so the tokenizer
71
+ * can keep the raw slice and the decoded value in step.
72
+ *
73
+ * The default branch is the one the previous implementation got wrong, and the
74
+ * documentation is explicit about it: "The backslash loses its special meaning i.e. it is
75
+ * interpreted literally should it precede characters other than the ones listed below."
76
+ * So an unlisted `\c` decodes to BOTH characters — `\z` is a backslash and a `z`, not a
77
+ * `z` — which is what lets `'Hello 100\%'` reach a `LIKE` pattern intact.
78
+ *
79
+ * @see https://clickhouse.com/docs/sql-reference/syntax#string
80
+ */
81
+ function decodeEscape(statement, index) {
82
+ const next = statement[index + 1];
83
+ // A trailing backslash: nothing follows it to escape, so it is itself.
84
+ if (next === undefined)
85
+ return { text: '\\', consumed: 1 };
86
+ if (next === 'x') {
87
+ // `\xHH`: an 8-bit character. Exactly two hex digits, as the server's own parser
88
+ // reads. Anything else is not the escape, so the backslash stays literal.
89
+ const hex = statement.slice(index + 2, index + 4);
90
+ if (HEX_PAIR.test(hex)) {
91
+ return { text: String.fromCharCode(Number.parseInt(hex, 16)), consumed: 4 };
92
+ }
93
+ return { text: '\\x', consumed: 2 };
94
+ }
95
+ // `\N` is reserved and does nothing: `SELECT 'a\Nb'` returns `ab`.
96
+ if (next === 'N')
97
+ return { text: '', consumed: 2 };
98
+ const decoded = ESCAPE_DECODE.get(next);
99
+ if (decoded !== undefined)
100
+ return { text: decoded, consumed: 2 };
101
+ return { text: `\\${next}`, consumed: 2 };
102
+ }
103
+ /**
104
+ * The C-style SOURCE spelling of a decoded value, inverting {@link CLICKHOUSE_ESCAPES}.
105
+ *
106
+ * `decode(escapeClickHouseString(value)) === value` for every value, which is the property
107
+ * redaction needs: a secret's raw and decoded spellings have to be two views of one string,
108
+ * or one of them survives into an error message.
109
+ */
110
+ export function escapeClickHouseString(value) {
111
+ let escaped = '';
112
+ for (const char of value) {
113
+ escaped += ESCAPE_ENCODE.get(char) ?? char;
114
+ }
115
+ return escaped;
116
+ }
117
+ /**
118
+ * Split a statement into words, quoted values and single punctuation characters.
119
+ *
120
+ * Comments (`--`, `#`, `/* … *\/`) are dropped. Quoted values are returned DECODED — the
121
+ * doubling and backslash escapes ClickHouse accepts are resolved — because both callers
122
+ * compare against the value the server sees. The SOURCE slice is returned as well, because
123
+ * the server may echo back either spelling.
124
+ */
125
+ export function tokenizeClickHouseSql(statement) {
126
+ const tokens = [];
127
+ let index = 0;
128
+ while (index < statement.length) {
129
+ const char = statement[index];
130
+ // -- line comment / # line comment
131
+ if ((char === '-' && statement[index + 1] === '-') || char === '#') {
132
+ const newline = statement.indexOf('\n', index);
133
+ index = newline === -1 ? statement.length : newline + 1;
134
+ continue;
135
+ }
136
+ // /* block comment */
137
+ if (char === '/' && statement[index + 1] === '*') {
138
+ const end = statement.indexOf('*/', index + 2);
139
+ index = end === -1 ? statement.length : end + 2;
140
+ continue;
141
+ }
142
+ if (char === ' ' || char === '\t' || char === '\n' || char === '\r') {
143
+ index += 1;
144
+ continue;
145
+ }
146
+ if (char === "'" || char === '"' || char === '`') {
147
+ const quote = char;
148
+ let value = '';
149
+ index += 1;
150
+ const start = index;
151
+ // An unterminated literal ends at the end of the statement, and its source slice with it.
152
+ let end = statement.length;
153
+ while (index < statement.length) {
154
+ const current = statement[index];
155
+ if (current === '\\') {
156
+ // ClickHouse accepts C-style escapes inside quoted values; the table in
157
+ // CLICKHOUSE_ESCAPES is what says how each one decodes.
158
+ const { text, consumed } = decodeEscape(statement, index);
159
+ value += text;
160
+ index += consumed;
161
+ continue;
162
+ }
163
+ if (current === quote) {
164
+ if (statement[index + 1] === quote) {
165
+ // Doubled quote: an escaped quote, not the end of the value.
166
+ value += quote;
167
+ index += 2;
168
+ continue;
169
+ }
170
+ end = index;
171
+ index += 1;
172
+ break;
173
+ }
174
+ value += current;
175
+ index += 1;
176
+ }
177
+ tokens.push({ kind: 'quoted', value, raw: statement.slice(start, end), quote });
178
+ continue;
179
+ }
180
+ if (WORD_START.test(char)) {
181
+ let value = '';
182
+ while (index < statement.length && WORD_BODY.test(statement[index])) {
183
+ value += statement[index];
184
+ index += 1;
185
+ }
186
+ tokens.push({ kind: 'word', value });
187
+ continue;
188
+ }
189
+ tokens.push({ kind: 'punct', value: char });
190
+ index += 1;
191
+ }
192
+ return tokens;
193
+ }
194
+ function isWord(token, keyword) {
195
+ return token?.kind === 'word' && token.value.toLowerCase() === keyword;
196
+ }
197
+ /** The value an identifier position carries, whatever quoting style spelled it. */
198
+ function identifierValue(token) {
199
+ if (!token)
200
+ return undefined;
201
+ if (token.kind === 'word')
202
+ return token.value;
203
+ if (token.kind === 'quoted')
204
+ return token.value;
205
+ return undefined;
206
+ }
207
+ /**
208
+ * Whether the statement carries `ON CLUSTER <cluster>` naming exactly this cluster.
209
+ *
210
+ * Case-insensitive in the keywords, exact in the cluster name, and indifferent to how
211
+ * the name is spelled — bare, backtick-quoted, double-quoted or single-quoted are all the
212
+ * same identifier to ClickHouse. A match inside a string literal cannot be mistaken for
213
+ * the real clause because the lexer has already resolved literals into `quoted` tokens.
214
+ */
215
+ export function statementTargetsCluster(statement, cluster) {
216
+ const tokens = tokenizeClickHouseSql(statement);
217
+ for (let index = 0; index + 2 < tokens.length; index += 1) {
218
+ if (!isWord(tokens[index], 'on') || !isWord(tokens[index + 1], 'cluster'))
219
+ continue;
220
+ if (identifierValue(tokens[index + 2]) === cluster)
221
+ return true;
222
+ }
223
+ return false;
224
+ }
225
+ /** Statement keywords that are session-scoped, and so can never be cluster-wide. */
226
+ const SESSION_SCOPE_KEYWORDS = new Set(['use', 'set']);
227
+ /**
228
+ * The leading keyword, lowercased — `undefined` for a statement that starts with anything
229
+ * other than a bare word.
230
+ */
231
+ export function leadingKeyword(statement) {
232
+ const first = tokenizeClickHouseSql(statement)[0];
233
+ return first?.kind === 'word' ? first.value.toLowerCase() : undefined;
234
+ }
235
+ /**
236
+ * Prove that a statement applies to every server, under `execution.mode: 'onCluster'`.
237
+ *
238
+ * EXACTLY ONE proof is accepted: the statement carries `ON CLUSTER <cluster>`, naming the
239
+ * configured cluster, so the initiating server distributes it through Keeper's DDL queue.
240
+ *
241
+ * Nothing is INFERRED from the statement's shape. An earlier version accepted a clause-free
242
+ * statement whose dotted references were all on a `replicatedDatabases` allow-list, which
243
+ * keyed on the references rather than on the DDL TARGET: `CREATE TABLE events AS
244
+ * analytics.source` passed the check while creating `events` on one server only. Deciding
245
+ * this properly means parsing the target of every DDL form ClickHouse accepts, and a
246
+ * parser that is subtly wrong here silently half-applies a schema — so the safe rule is
247
+ * the explicit one, and the author writes the clause.
248
+ *
249
+ * The statement is never rewritten. Adding `ON CLUSTER` on the author's behalf would
250
+ * change the semantics of DDL TypeKro did not write, and getting that wrong on a
251
+ * production cluster is not recoverable.
252
+ *
253
+ * Statements that legitimately cannot carry the clause — `SET`, `USE`, a single-node
254
+ * `SYSTEM …`, `INSERT` — do not belong under `onCluster` at all; `fanout` runs them on
255
+ * every server itself, and reaching every server is then the author's business.
256
+ */
257
+ export function validateOnClusterStatement(statement, cluster) {
258
+ if (statementTargetsCluster(statement, cluster))
259
+ return undefined;
260
+ const keyword = leadingKeyword(statement);
261
+ if (keyword !== undefined && SESSION_SCOPE_KEYWORDS.has(keyword)) {
262
+ return (`starts with '${keyword.toUpperCase()}', which is session-scoped and applies only to ` +
263
+ `the one server it runs on; statements that cannot carry an 'ON CLUSTER' clause ` +
264
+ `belong under execution.mode 'fanout'`);
265
+ }
266
+ return (`carries no 'ON CLUSTER ${cluster}' clause, which is the only thing that makes a ` +
267
+ `single execution reach every server; add the clause, or use execution.mode 'fanout'`);
268
+ }
269
+ /**
270
+ * Keywords whose following value is a credential.
271
+ *
272
+ * `IDENTIFIED BY` is handled separately: it is the two-word form of the same idea.
273
+ */
274
+ const SECRET_KEYWORDS = new Set([
275
+ 'password',
276
+ 'token',
277
+ 'access_key_id',
278
+ 'secret_access_key',
279
+ 'aws_access_key_id',
280
+ 'aws_secret_access_key',
281
+ ]);
282
+ /**
283
+ * Below this length a "secret" is not one, and blanking it out of the server's message
284
+ * would destroy the message without protecting anything.
285
+ */
286
+ const MIN_SECRET_LENGTH = 3;
287
+ /** `'` doubled, the spelling `''` comes from. */
288
+ function doubleQuoteEscaped(value) {
289
+ return value.replaceAll("'", "''");
290
+ }
291
+ /**
292
+ * Every spelling of one literal that could appear in the server's output.
293
+ *
294
+ * A credential containing a quote, a backslash or a control character has TWO source
295
+ * spellings (`pa\'ss` and `pa''ss`) plus the decoded value (`pa'ss`), and ClickHouse echoes
296
+ * back whichever one it feels like — frequently the source form, since what it is
297
+ * complaining about is the text it was given. Redacting only the decoded value therefore
298
+ * leaves the escaped form of the secret sitting in the error. All of them are returned; for
299
+ * the overwhelmingly common literal that contains none of those characters they collapse to
300
+ * a single string.
301
+ *
302
+ * The re-escaped form comes from {@link escapeClickHouseString}, which inverts the very
303
+ * table the decoder read, so the decoded value and its C-style spelling are guaranteed to be
304
+ * two views of one string rather than two independently-guessed ones.
305
+ */
306
+ function secretForms(token) {
307
+ if (token === undefined || token.kind === 'punct')
308
+ return [];
309
+ if (token.kind === 'word')
310
+ return [token.value];
311
+ return [
312
+ token.value,
313
+ token.raw,
314
+ escapeClickHouseString(token.value),
315
+ doubleQuoteEscaped(token.value),
316
+ ];
317
+ }
318
+ /**
319
+ * Every value in the SUBMITTED statement that must not survive into a captured message,
320
+ * in every spelling it could be echoed in, LONGEST FIRST.
321
+ *
322
+ * Deliberately over-broad: EVERY single-quoted literal counts, not only the ones a
323
+ * keyword introduces. That is the whole point — the case keyword matching misses is the
324
+ * positional one, `S3('https://…', '<key id>', '<secret>', 'CSV')`, where nothing in the
325
+ * text says which argument is the credential. Redacting a harmless literal costs a word
326
+ * of an error message; leaking the other kind costs the key.
327
+ *
328
+ * Longest first so that replacing one form cannot leave a shorter form of the same secret
329
+ * stranded inside what is left of a longer one.
330
+ */
331
+ export function extractStatementSecrets(statement) {
332
+ const tokens = tokenizeClickHouseSql(statement);
333
+ const secrets = new Set();
334
+ const add = (values) => {
335
+ for (const value of values) {
336
+ if (value.length >= MIN_SECRET_LENGTH)
337
+ secrets.add(value);
338
+ }
339
+ };
340
+ for (let index = 0; index < tokens.length; index += 1) {
341
+ const token = tokens[index];
342
+ if (token?.kind === 'quoted' && token.quote === "'") {
343
+ add(secretForms(token));
344
+ continue;
345
+ }
346
+ if (token?.kind !== 'word')
347
+ continue;
348
+ const keyword = token.value.toLowerCase();
349
+ let cursor = index + 1;
350
+ if (keyword === 'identified') {
351
+ if (!isWord(tokens[cursor], 'by'))
352
+ continue;
353
+ cursor += 1;
354
+ // `IDENTIFIED WITH sha256_password BY '…'` also lands here via the BY token.
355
+ }
356
+ else if (!SECRET_KEYWORDS.has(keyword)) {
357
+ continue;
358
+ }
359
+ // Step over an assignment or separator between the keyword and its value.
360
+ while (tokens[cursor]?.kind === 'punct' &&
361
+ ['=', ':', '(', ','].includes(tokens[cursor]?.value ?? '')) {
362
+ cursor += 1;
363
+ }
364
+ add(secretForms(tokens[cursor]));
365
+ }
366
+ return [...secrets].sort((left, right) => right.length - left.length || (left < right ? -1 : left > right ? 1 : 0));
367
+ }
368
+ //# sourceMappingURL=sql.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.js","sourceRoot":"","sources":["../../../src/alchemy/clickhouse-schema/sql.ts"],"names":[],"mappings":"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"}