@starci/eslint-canon-fe 9.4.7 → 9.5.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 +15 -0
- package/dist/fe-stack.d.ts +3 -3
- package/dist/fe-stack.js +3 -9
- package/dist/index.js +0 -2
- package/dist/lib/scope.d.ts +8 -0
- package/dist/lib/scope.js +10 -0
- package/dist/lib/why.js +2 -2
- package/dist/shape-slot.d.ts +2 -2
- package/dist/transport.d.ts +1 -1
- package/dist/transport.js +29 -7
- package/package.json +1 -1
- package/runtime/knowledge/hfs/canon-pins.yaml +54 -24
- package/runtime/knowledge/hfs/fe-stack.yaml +4 -11
- package/runtime/knowledge/hfs/slots.yaml +185 -174
- package/runtime/scripts/hfs/architecture/canon-clones.mjs +1 -1
- package/runtime/scripts/hfs/architecture/{supabase-be.mjs → identity.mjs} +45 -15
- package/runtime/scripts/hfs/architecture/index.mjs +2 -3
- package/runtime/scripts/hfs/architecture/{supabase-ast.mjs → jwt-ast.mjs} +2 -103
- package/runtime/scripts/hfs/architecture/register-once.mjs +1 -1
- package/runtime/scripts/hfs/architecture/schema-owner.mjs +29 -4
- package/runtime/scripts/hfs/architecture/server-action.mjs +3 -4
- package/runtime/scripts/hfs/architecture/side-boundary.mjs +1 -1
- package/runtime/scripts/hfs/architecture/{supabase-keys.mjs → sql-keys.mjs} +1 -1
- package/runtime/scripts/hfs/architecture/sql-owner.mjs +25 -27
- package/runtime/scripts/hfs/architecture/transport-owner.mjs +7 -3
- package/runtime/scripts/hfs/declaration-shape.mjs +15 -18
- package/runtime/scripts/hfs/manifest-shape.mjs +4 -4
- package/runtime/scripts/hfs/rule-params-shape.mjs +4 -1
- package/runtime/scripts/hfs/rules/database-constants.mjs +8 -10
- package/runtime/scripts/hfs/rules/database-migrations.mjs +3 -3
- package/runtime/scripts/hfs/slot-app-view.mjs +1 -1
- package/runtime/scripts/hfs/slots.mjs +8 -2
- package/runtime/scripts/lib/secret-patterns.mjs +2 -2
- package/dist/callback-shape.d.ts +0 -7
- package/dist/callback-shape.js +0 -396
- package/dist/lib/pure-owner-helper.d.ts +0 -10
- package/dist/lib/pure-owner-helper.js +0 -156
- package/runtime/scripts/hfs/architecture/supabase-tables.mjs +0 -50
- package/runtime/scripts/hfs/architecture/supabase.mjs +0 -226
|
@@ -2,27 +2,23 @@
|
|
|
2
2
|
// against a loaded manifest remain in slots.mjs; this module mirrors modules/schemas/hfs-repo.schema.yaml only.
|
|
3
3
|
import { isPlainObject } from '../../engine/plain-object.mjs';
|
|
4
4
|
import { APP_KIND, connectionShapeProblems, NAME, PACKAGE_NAME, RUNTIME_KIND, SLOT_ID } from './manifest-shape.mjs';
|
|
5
|
+
import { dbFunctionsOk } from './rule-params-shape.mjs';
|
|
5
6
|
import { kindShapeProblems, patternShapeProblems } from './declaration-slots.mjs';
|
|
6
7
|
import { byCodeUnit } from '../lib/list.mjs';
|
|
7
8
|
|
|
8
|
-
/** Shape problems of the optional hfs.json `
|
|
9
|
-
const
|
|
9
|
+
/** Shape problems of the optional hfs.json `db` block of a lite app: the environment variable naming its database, its image, forced RLS and its application role. */
|
|
10
|
+
const isStringList = (value) => Array.isArray(value) && value.every((entry) => typeof entry === 'string' && entry.trim());
|
|
10
11
|
|
|
11
|
-
function
|
|
12
|
-
const bad = [];
|
|
13
|
-
if (block.enableSignup !== undefined && typeof block.enableSignup !== 'boolean') bad.push('supabase.enableSignup must be true or false');
|
|
14
|
-
if (block.jwtExpiry !== undefined && !(Number.isInteger(block.jwtExpiry) && block.jwtExpiry > 0 && block.jwtExpiry <= 3600)) bad.push('supabase.jwtExpiry must be an integer of seconds, 3600 at most');
|
|
15
|
-
if (block.siteUrl !== undefined && (typeof block.siteUrl !== 'string' || !block.siteUrl.trim())) bad.push('supabase.siteUrl must be a URL string');
|
|
16
|
-
for (const key of ['redirectUrls', 'forceRls']) if (block[key] !== undefined && !isSupabaseStringList(block[key])) bad.push(`supabase.${key} must be a list of strings`);
|
|
17
|
-
return bad;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function supabaseBlockProblems(block) {
|
|
12
|
+
function dbBlockProblems(block) {
|
|
21
13
|
if (block === undefined) return [];
|
|
22
|
-
if (!isPlainObject(block)) return ['
|
|
14
|
+
if (!isPlainObject(block)) return ['db must be an object'];
|
|
23
15
|
const bad = [];
|
|
24
|
-
for (const key of Object.keys(block)) if (!['
|
|
25
|
-
|
|
16
|
+
for (const key of Object.keys(block)) if (!['urlEnv', 'image', 'forceRls', 'forceRlsExemptions', 'appRole'].includes(key)) bad.push(`db has unknown key ${key}`);
|
|
17
|
+
if (block.urlEnv !== undefined && (typeof block.urlEnv !== 'string' || !/^[A-Z][A-Z0-9_]*$/.test(block.urlEnv))) bad.push('db.urlEnv must name an UPPER_CASE environment variable');
|
|
18
|
+
if (block.image !== undefined && (typeof block.image !== 'string' || !/@sha256:[0-9a-f]{64}$/.test(block.image))) bad.push('db.image must be a digest-pinned image reference');
|
|
19
|
+
if (block.forceRls !== undefined && !isStringList(block.forceRls)) bad.push('db.forceRls must be a list of strings');
|
|
20
|
+
if (block.appRole !== undefined && (typeof block.appRole !== 'string' || !/^[a-z][a-z0-9_]*$/.test(block.appRole))) bad.push('db.appRole must name a role');
|
|
21
|
+
if (block.forceRlsExemptions !== undefined && !Array.isArray(block.forceRlsExemptions)) bad.push('db.forceRlsExemptions must be a list of { table, reason }');
|
|
26
22
|
return bad;
|
|
27
23
|
}
|
|
28
24
|
|
|
@@ -95,7 +91,8 @@ function declarationSideProblems(side, value, names) {
|
|
|
95
91
|
const bad = [];
|
|
96
92
|
const at = `sides.${side}`;
|
|
97
93
|
if (!isPlainObject(value)) return [`${at} must be an object`];
|
|
98
|
-
for (const key of Object.keys(value)) if (!['apps', 'optionalSlots', 'patterns', 'kinds', 'connections', 'reads', 'extraPackages', 'grammar', 'backing', 'queueOutbox'].includes(key)) bad.push(`${at} has unknown key ${key}`);
|
|
94
|
+
for (const key of Object.keys(value)) if (!['apps', 'optionalSlots', 'patterns', 'kinds', 'connections', 'reads', 'extraPackages', 'grammar', 'backing', 'queueOutbox', 'dbFunctions'].includes(key)) bad.push(`${at} has unknown key ${key}`);
|
|
95
|
+
if (value.dbFunctions !== undefined && (side !== 'be' || !dbFunctionsOk(value.dbFunctions))) bad.push(`${at}.dbFunctions belongs to the be side and lists {name, reason} database functions with unique names`);
|
|
99
96
|
bad.push(...appShapeProblems(value.apps, at, side, names));
|
|
100
97
|
if (isBadUniqueList(value.optionalSlots, (slot) => SLOT_ID.test(String(slot)))) bad.push(`${at}.optionalSlots must be a unique list of slot ids`);
|
|
101
98
|
if (value.backing !== undefined && side !== 'be') bad.push('backing belongs to the be side');
|
|
@@ -127,13 +124,13 @@ function observeBlockProblems(observe) {
|
|
|
127
124
|
return bad;
|
|
128
125
|
}
|
|
129
126
|
|
|
130
|
-
const DECLARATION_KEYS = new Set(['hfs', 'kind', 'project', 'edition', '
|
|
127
|
+
const DECLARATION_KEYS = new Set(['hfs', 'kind', 'project', 'edition', 'db', 'sides', 'browser', 'lexicon', 'observe']);
|
|
131
128
|
const RUNTIME_DECLARATION_KEYS = new Set(['hfs', 'kind', 'project']);
|
|
132
129
|
|
|
133
130
|
function productDeclarationProblems(declaration, profiles) {
|
|
134
131
|
const bad = [];
|
|
135
132
|
for (const key of Object.keys(declaration)) if (!DECLARATION_KEYS.has(key)) bad.push(`unknown key ${key}`);
|
|
136
|
-
bad.push(...
|
|
133
|
+
bad.push(...dbBlockProblems(declaration.db), ...lexiconBlockProblems(declaration.lexicon), ...observeBlockProblems(declaration.observe));
|
|
137
134
|
if (declaration.browser !== undefined && declaration.browser !== true) bad.push('browser is `true` when the app has a browser journey (slot app.browser), and is left out otherwise');
|
|
138
135
|
if (declaration.kind !== APP_KIND) bad.push(`kind must be ${APP_KIND} (a product is one app repository with a be and an fe side) or ${RUNTIME_KIND} (the StarCi runtime repository)`);
|
|
139
136
|
if (!isPlainObject(declaration.sides) || Object.keys(declaration.sides).sort(byCodeUnit).join() !== profiles.join()) { bad.push('sides must declare exactly be and fe'); return bad; }
|
|
@@ -15,12 +15,12 @@ const ENV_PREFIX =/^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/;
|
|
|
15
15
|
const CONTEXT_ISOLATIONS = Object.freeze(["database", "schema"]);
|
|
16
16
|
/** The app kinds that may own a context: the services, never the migrate or cli apps that only run migrations. */
|
|
17
17
|
const CONTEXT_OWNER_KINDS = Object.freeze(["api", "worker"]);
|
|
18
|
-
/** The database
|
|
19
|
-
const CONNECTION_PROVIDERS = Object.freeze(["postgres"
|
|
18
|
+
/** The database engine a connection runs on. */
|
|
19
|
+
const CONNECTION_PROVIDERS = Object.freeze(["postgres"]);
|
|
20
20
|
/** The editions an app repository may declare in hfs.json (`full` when absent): the filter slots.mjs applies. */
|
|
21
21
|
export const EDITIONS = Object.freeze(["full", "lite"]);
|
|
22
|
-
/** What decides where schema changes live (ruleParams.<side>.schemaAuthority): TypeORM migrations under persistence/, or the
|
|
23
|
-
export const SCHEMA_AUTHORITIES = Object.freeze(["typeorm", "
|
|
22
|
+
/** What decides where schema changes live (ruleParams.<side>.schemaAuthority): TypeORM migrations under persistence/, or the SQL migration tree db/migrations. */
|
|
23
|
+
export const SCHEMA_AUTHORITIES = Object.freeze(["typeorm", "sql"]);
|
|
24
24
|
/**
|
|
25
25
|
* The shape problems of the `connections` of one side: a list of {name, envPrefix, owner, isolation}, the owner an api or worker app
|
|
26
26
|
* of the same side (a connection is a bounded context and one service owns it), isolation `database` or `schema`.
|
|
@@ -62,6 +62,9 @@ function beSpecificProblems(be, manifest) {
|
|
|
62
62
|
return bad;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
/** True for an absent list or a list of {name, reason} database functions, names unique. */
|
|
66
|
+
export const dbFunctionsOk = (list) => list === undefined || (Array.isArray(list) && list.every((entry) => isPlainObject(entry) && Object.keys(entry).sort().join() === 'name,reason' && /^[a-z_][a-z0-9_]*(?:\.[a-z_][a-z0-9_]*)?$/.test(entry.name) && typeof entry.reason === 'string' && entry.reason.trim().length > 0) && new Set(list.map((entry) => entry.name)).size === list.length);
|
|
67
|
+
|
|
65
68
|
/** The shape problems of `m.ruleParams`. */
|
|
66
69
|
export function ruleParamsProblems(m) {
|
|
67
70
|
const bad = [];
|
|
@@ -71,7 +74,7 @@ export function ruleParamsProblems(m) {
|
|
|
71
74
|
// common holds the parameters both sides share; a side may restate one of them (a valid value) as an override, nothing else.
|
|
72
75
|
// Edition lite: a side's optional `lite` map overrides keys of the same side (never `lite` itself) when the app declares edition lite.
|
|
73
76
|
if (!sideOk(rp.common, []) || !fileLinesOk(rp.common.fileLines) || !blockOk(rp.common.duplicateBlock)) bad.push('ruleParams.common needs fileLines {soft, hardGrowth} and duplicateBlock {lines >= 2, tokens >= 1}; optional functionLines and featureFiles must be positive integers');
|
|
74
|
-
if (!sideOk(rp.be, BE_OWN, ['schemaAuthority', 'lite']) || (rp.be.schemaAuthority !== undefined && !SCHEMA_AUTHORITIES.includes(rp.be.schemaAuthority)) || !liteOk(rp.be.lite, [...BE_OWN, ...SHARED_KEYS, 'schemaAuthority'])) bad.push('ruleParams.be needs infraOwners, eventBus, specDoubles, paramNames, suffixes, bannedSuffixes, contractShape {helper}, unitRoles, logicRoles, thinRoles, patternScenarios, kindPatterns, addKinds and backing (shared parameters live in ruleParams.common, a side may override them); optional: schemaAuthority (' + SCHEMA_AUTHORITIES.join(' | ') + ') and lite (overrides of the same keys)'); else bad.push(...unitRolesProblems(rp.be), ...roleListProblems(rp.be));
|
|
77
|
+
if (!sideOk(rp.be, BE_OWN, ['schemaAuthority', 'lite', 'dbFunctions']) || (rp.be.schemaAuthority !== undefined && !SCHEMA_AUTHORITIES.includes(rp.be.schemaAuthority)) || !dbFunctionsOk(rp.be.dbFunctions) || !liteOk(rp.be.lite, [...BE_OWN, ...SHARED_KEYS, 'schemaAuthority', 'dbFunctions'])) bad.push('ruleParams.be needs infraOwners, eventBus, specDoubles, paramNames, suffixes, bannedSuffixes, contractShape {helper}, unitRoles, logicRoles, thinRoles, patternScenarios, kindPatterns, addKinds and backing (shared parameters live in ruleParams.common, a side may override them); optional: schemaAuthority (' + SCHEMA_AUTHORITIES.join(' | ') + '), dbFunctions ([{name, reason}]) and lite (overrides of the same keys)'); else bad.push(...unitRolesProblems(rp.be), ...roleListProblems(rp.be));
|
|
75
78
|
bad.push(...beSpecificProblems(rp.be, m));
|
|
76
79
|
if (rp.fe !== undefined && (!sideOk(rp.fe, [], ['lite']) || !liteOk(rp.fe.lite, SHARED_KEYS))) bad.push('ruleParams.fe may only restate the shared parameters of ruleParams.common, and carry a lite override of them');
|
|
77
80
|
if (!dbParamsOk(rp.db)) bad.push('ruleParams.db may contain only extensions (a list of unique non-empty extension names) and queueOutbox ({table: <schema>.<table>, columns: [unique column names including queue]})');
|
|
@@ -1,26 +1,24 @@
|
|
|
1
|
-
// Single source of database-rule finding codes and owned
|
|
1
|
+
// Single source of database-rule finding codes and the owned db/ paths of a lite app (slot app.db).
|
|
2
2
|
export const DB_MIGRATION_SHAPE = 'DB_MIGRATION_SHAPE';
|
|
3
3
|
export const DB_RLS_REQUIRED = 'DB_RLS_REQUIRED';
|
|
4
4
|
export const DB_DYNAMIC_DDL = 'DB_DYNAMIC_DDL';
|
|
5
5
|
export const DB_POLICY_SHAPE = 'DB_POLICY_SHAPE';
|
|
6
6
|
export const DB_DEFINER_SAFE = 'DB_DEFINER_SAFE';
|
|
7
7
|
export const DB_STORAGE_POLICY = 'DB_STORAGE_POLICY';
|
|
8
|
-
export const
|
|
9
|
-
export const DB_TYPES_DRIFT = 'DB_TYPES_DRIFT';
|
|
8
|
+
export const LITE_DB_MIGRATION = 'LITE_DB_MIGRATION';
|
|
10
9
|
export const DB_BASELINE_SHAPE = 'DB_BASELINE_SHAPE';
|
|
11
10
|
export const DB_ARCHIVE_MUTATED = 'DB_ARCHIVE_MUTATED';
|
|
12
11
|
export const DB_PGMQ_DECLARED = 'DB_PGMQ_DECLARED';
|
|
13
12
|
export const DB_CRON_OWNED = 'DB_CRON_OWNED';
|
|
14
13
|
export const DB_EXTENSION_ALLOWED = 'DB_EXTENSION_ALLOWED';
|
|
15
|
-
export const DB_API_EXPOSED = 'DB_API_EXPOSED';
|
|
16
14
|
export const DB_MIGRATION_DESTRUCTIVE = 'DB_MIGRATION_DESTRUCTIVE';
|
|
17
15
|
export const HFS_SEED_PII = 'HFS_SEED_PII';
|
|
18
16
|
export const DB_VAULT_WRITE = 'DB_VAULT_WRITE';
|
|
19
17
|
|
|
20
|
-
export const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
18
|
+
export const DB_DIR = 'db';
|
|
19
|
+
export const MIGRATIONS_DIR = `${DB_DIR}/migrations`;
|
|
20
|
+
/** The migrations retired at a baseline cutover (slot app.db.migrations.archive): never applied, never judged by L02-L08. */
|
|
21
|
+
export const MIGRATIONS_ARCHIVE_DIR = `${MIGRATIONS_DIR}/archive`;
|
|
22
|
+
/** True for a migration `starci app db migrate` applies: a path under db/migrations/ outside the archive. */
|
|
24
23
|
export const isActiveMigration = (file) => file.startsWith(`${MIGRATIONS_DIR}/`) && !file.startsWith(`${MIGRATIONS_ARCHIVE_DIR}/`);
|
|
25
|
-
export const
|
|
26
|
-
export const TYPES_FILE = 'supabase/types/database.types.ts';
|
|
24
|
+
export const SEED_FILE = `${DB_DIR}/seed.sql`;
|
|
@@ -74,7 +74,7 @@ function localMigrationFindings(local) {
|
|
|
74
74
|
const stamps = new Map();
|
|
75
75
|
for (const entry of local) {
|
|
76
76
|
if (!entry.match) {
|
|
77
|
-
findings.push(found(DB_MIGRATION_SHAPE, entry.file, `${entry.file} is not named <ts14>_<kebab>.sql; a migration is created by \`npm run db:new\` (
|
|
77
|
+
findings.push(found(DB_MIGRATION_SHAPE, entry.file, `${entry.file} is not named <ts14>_<kebab>.sql; a migration is created by \`npm run db:new\` (starci app db new), never renamed by hand`, { expected: '<ts14>_<kebab>.sql' }));
|
|
78
78
|
continue;
|
|
79
79
|
}
|
|
80
80
|
const stamp = migrationStamp(entry.match[1]);
|
|
@@ -143,8 +143,8 @@ function removedMigrationFindings(local, retired, baseNames, baseSha) {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
/**
|
|
146
|
-
* L02 findings for names, stamps, ordering and immutability of
|
|
147
|
-
*
|
|
146
|
+
* L02 findings for names, stamps, ordering and immutability of db/migrations/*.sql. `archived` are the files of
|
|
147
|
+
* db/migrations/archive/ (app.db.migrations.archive): never judged, and a migration moved there at a baseline
|
|
148
148
|
* cutover is retired from the ordering chain, not removed. New files append after HEAD's active migrations; timestamps
|
|
149
149
|
* on archived migrations, remote branches and the wall clock do not constrain a replacement baseline.
|
|
150
150
|
*/
|
|
@@ -49,7 +49,7 @@ function sideCrossing(repo, fromSide, toSide, toPath) {
|
|
|
49
49
|
function importAllowedApp({ repo, root, sides }, fromPath, toPath) {
|
|
50
50
|
const from = splitSide(fromPath);
|
|
51
51
|
const to = splitSide(toPath);
|
|
52
|
-
// A side file may read an app-root path (
|
|
52
|
+
// A side file may read an app-root path (db/types/) only through a declared read, exactly as it reads the other side.
|
|
53
53
|
if (from && from.side !== to?.side) return sideCrossing(repo, from.side, to?.side ?? null, toPath);
|
|
54
54
|
if (from && to) return sides[from.side].importAllowed(from.rest, to.rest);
|
|
55
55
|
return root.importAllowed(fromPath, toPath);
|
|
@@ -120,6 +120,7 @@ function sideDeclaration(manifest, declaration, name, edition, providers) {
|
|
|
120
120
|
connections: Object.freeze((s.connections ?? []).map(connectionView)),
|
|
121
121
|
providers,
|
|
122
122
|
reads: Object.freeze([...(s.reads ?? [])]),
|
|
123
|
+
dbFunctions: Object.freeze((s.dbFunctions ?? []).map((entry) => Object.freeze({ ...entry }))),
|
|
123
124
|
...(s.grammar === undefined ? {} : { grammar: s.grammar }),
|
|
124
125
|
...(s.extraPackages === undefined ? {} : { extraPackages: Object.freeze(s.extraPackages.map(entry => Object.freeze({ ...entry }))) }),
|
|
125
126
|
manifestVersion: manifest.version,
|
|
@@ -221,7 +222,8 @@ function createScopeResolver(manifest, repo) {
|
|
|
221
222
|
trackingOf,
|
|
222
223
|
/** True only for a path a slot owns and requires to be committed. */
|
|
223
224
|
isTracked: (p) => trackingOf(p) === 'tracked',
|
|
224
|
-
|
|
225
|
+
// The app's own database functions (hfs.json sides.be.dbFunctions) join the canon's list (R334).
|
|
226
|
+
ruleParams: () => withDeclaredDbFunctions(ruleParams(manifest, profile, edition), repo.dbFunctions),
|
|
225
227
|
allowedImports: (tier) => manifest.tiers[profile]?.[tier]?.mayImport ?? null,
|
|
226
228
|
});
|
|
227
229
|
}
|
|
@@ -235,13 +237,17 @@ function createScopeResolver(manifest, repo) {
|
|
|
235
237
|
*/
|
|
236
238
|
export function createSlotResolver(manifest, repo) {
|
|
237
239
|
if (repo.profile !== APP_SCOPE) return createScopeResolver(manifest, repo);
|
|
238
|
-
// The root declares no connection of its own, yet a provider slot of the app profile
|
|
240
|
+
// The root declares no connection of its own, yet a provider slot of the app profile is enabled by a
|
|
239
241
|
// side's connection with that provider: the root scope reads the union of the sides' connections.
|
|
240
242
|
const root = createScopeResolver(manifest, { ...repo, connections: SIDES.flatMap((side) => repo.sides[side].connections) });
|
|
241
243
|
const sides = Object.fromEntries(PROFILES.map((side) => [side, createScopeResolver(manifest, repo.sides[side])]));
|
|
242
244
|
return appResolver(repo, root, sides);
|
|
243
245
|
}
|
|
244
246
|
|
|
247
|
+
/** The rule parameters with the app's declared database functions appended to `dbFunctions` (be only), frozen. */
|
|
248
|
+
const withDeclaredDbFunctions = (params, declared = []) => (params.dbFunctions === undefined && !declared.length ? params
|
|
249
|
+
: Object.freeze({ ...params, dbFunctions: Object.freeze([...(params.dbFunctions ?? []), ...declared]) }));
|
|
250
|
+
|
|
245
251
|
/** The rule parameters of one profile (be: infraOwners, suffixes, bannedSuffixes and the rest over the shared ruleParams.common fileLines and duplicateBlock; fe: common alone or with its overrides; runtime: ruleParams.runtime of a runtime manifest), as a frozen deep copy. Under `edition` lite the `lite` overrides of ruleParams.<profile> merge over the base (the `lite` key itself is never returned). */
|
|
246
252
|
export function ruleParams(manifest, profile, edition = 'full') {
|
|
247
253
|
const profiles = manifestKind(manifest) === RUNTIME_KIND ? [RUNTIME_KIND] : PROFILES;
|
|
@@ -100,7 +100,7 @@ const SECRET_NAME_TEST = NAME_WORD(SECRET_WORD, String.raw`(?:[_\-.]|[A-Z]|[^A-Z
|
|
|
100
100
|
const BENIGN_TAIL_TEST = NAME_WORD(BENIGN_WORD, '$');
|
|
101
101
|
|
|
102
102
|
/** True when a bare variable `name` holds secret material as an identifier segment (DB_PASSWORD, dbPassword,
|
|
103
|
-
*
|
|
103
|
+
* STORAGE_SECRET_ACCESS_KEY) and does not end in a config suffix (PASSWORD_MIN_LENGTH, SECRET_FILE,
|
|
104
104
|
* tokenBudget). The same name judgement the `assigned-secret` patterns make, for callers that read keys. */
|
|
105
105
|
export const secretNameLike = (name) => SECRET_NAME_TEST.test(name) && !BENIGN_TAIL_TEST.test(name);
|
|
106
106
|
|
|
@@ -117,7 +117,7 @@ export const SECRET_PATTERNS = [
|
|
|
117
117
|
{ name: 'jwt', re: /\beyJ[A-Za-z0-9_-]{10,}\.eyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}/ },
|
|
118
118
|
{ name: 'age-secret-key', re: /\bAGE-SECRET-KEY-1[0-9A-Z]{20,}\b/ },
|
|
119
119
|
{ name: 'password-connection-string', re: /\b(?:postgres(?:ql)?|mysql|mariadb|mongodb(?:\+srv)?|redis):\/\/[^:\s/@]+:[^@\s/${}]{8,}@/iu },
|
|
120
|
-
// A value written `env(NAME)` (
|
|
120
|
+
// A value written `env(NAME)` (a config reference form) names a variable, not a secret.
|
|
121
121
|
// A keyword-assigned value that names itself a stand-in (a test stub's `accessToken: "fixture-..."`) is no
|
|
122
122
|
// candidate; only this heuristic takes the exemption, never a provider-shaped token above.
|
|
123
123
|
// A spec file's keyword-assigned values are test inputs (a spec's sign-in
|
package/dist/callback-shape.d.ts
DELETED
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { type Recommended, type Rules } from "./lib/rule.js";
|
|
2
|
-
/** A callback stays a PKCE exchange and redirect, with every side effect owned by the auth helper. */
|
|
3
|
-
export declare const callbackShape: import("./lib/rule.js").Rule<"shape", []>;
|
|
4
|
-
/** The rule R287 contributes to the front-end plugin. */
|
|
5
|
-
export declare const rules: Rules;
|
|
6
|
-
/** Every callback shape violation is an error. */
|
|
7
|
-
export declare const recommended: Recommended;
|