Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions packages/errors/__tests__/parse.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,20 +226,19 @@ describe('generated registry (full constructive-db audit)', () => {
// require_step_up() raises one code per factor so the client knows which
// re-verification to prompt for; a humanized code would prompt for the
// wrong one, so each needs its own copy.
// STEP_UP_REQUIRED_PASSWORD_OR_MFA is deliberately absent: constructive-db
// split it into the per-factor codes below (require_step_up.sql).
const factors = [
'STEP_UP_REQUIRED_PASSWORD',
'STEP_UP_REQUIRED_MFA',
'STEP_UP_REQUIRED_PASSWORD_OR_MFA',
'STEP_UP_REQUIRED_FRESH_AUTH'
];
for (const code of factors) {
expect(classify(code)).toBe('public');
expect(generatedRegistry[code].http).toBe(403);
expect(format(code)).not.toMatch(/^Step up required/);
}
expect(format('STEP_UP_REQUIRED_MFA')).not.toBe(
format('STEP_UP_REQUIRED_PASSWORD')
expect(new Set(factors.map((code) => format(code))).size).toBe(
factors.length
);
// An unrecognized posture fails closed rather than passing the mutation.
expect(classify('STEP_UP_INVALID_TYPE')).toBe('public');
Expand Down
7 changes: 7 additions & 0 deletions packages/errors/scripts/db-error-inventory.json
Original file line number Diff line number Diff line change
Expand Up @@ -5825,6 +5825,13 @@
"n_generated": 3,
"class": "public"
},
"STEP_UP_REQUIRED_PASSWORD_OR_MFA": {
"count": 2,
"dynamic": false,
"sample": "STEP_UP_REQUIRED_PASSWORD_OR_MFA",
"n_source": 1,
"n_generated": 1
},
"STORAGE_API_NOT_PROVISIONED": {
"count": 2,
"dynamic": false,
Expand Down
3 changes: 2 additions & 1 deletion packages/errors/scripts/generate-registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@ def add_copy(code, msg):
'STEP_UP_REQUIRED_FRESH_AUTH':
'Please verify your identity to continue.',
'STEP_UP_REQUIRED_PASSWORD_OR_MFA':
'Please verify your identity to continue.',
'Please re-enter your password or enter a code from your '
'authenticator app to continue.',
'STEP_UP_INVALID_TYPE':
'This action requires verification that is not configured correctly. '
'Please contact support.',
Expand Down
8 changes: 5 additions & 3 deletions packages/errors/src/generated/registry.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
/**
* GENERATED FILE — DO NOT EDIT BY HAND.
*
* Source of truth: the constructive-db error audit (817 distinct codes
* Source of truth: the constructive-db error audit (818 distinct codes
* raised via EXCEPTION/THROW across deploy sources + generated output).
* Regenerate with `python3 scripts/generate-registry.py` (see README.md).
*
* Public copy is seeded from the dashboard error catalogs; developer/invariant
* codes carry their raw message (with %-args rendered as {{argN}}). Curated
* entries in `registry.ts` override anything here (typed context + refined copy).
*
* Counts: 817 total, 598 public, 219 internal.
* Counts: 818 total, 599 public, 219 internal.
*/
import { defineError, type DefinedError } from '../define';
import type { ErrorContext } from '../types';
Expand Down Expand Up @@ -763,6 +763,7 @@ export const generatedRegistry: Record<string, DefinedError<ErrorContext>> = {
'STEP_UP_REQUIRED_FRESH_AUTH': defineError({ code: 'STEP_UP_REQUIRED_FRESH_AUTH', class: 'public', http: 403, message: 'Please verify your identity to continue.' }),
'STEP_UP_REQUIRED_MFA': defineError({ code: 'STEP_UP_REQUIRED_MFA', class: 'public', http: 403, message: 'Please enter a code from your authenticator app to continue.' }),
'STEP_UP_REQUIRED_PASSWORD': defineError({ code: 'STEP_UP_REQUIRED_PASSWORD', class: 'public', http: 403, message: 'Please re-enter your password to continue.' }),
'STEP_UP_REQUIRED_PASSWORD_OR_MFA': defineError({ code: 'STEP_UP_REQUIRED_PASSWORD_OR_MFA', class: 'public', http: 403, message: 'Please re-enter your password or enter a code from your authenticator app to continue.' }),
'STORAGE_API_NOT_PROVISIONED': defineError({ code: 'STORAGE_API_NOT_PROVISIONED', class: 'public', http: 400, message: 'Storage api not provisioned.' }),
'STORAGE_DESTINATION_REQUIRES_TEMP': defineError({ code: 'STORAGE_DESTINATION_REQUIRES_TEMP', class: 'internal', http: 500, message: 'Storage destination requires temp.' }),
'STORAGE_FILE_BUCKET_IMMUTABLE': defineError({ code: 'STORAGE_FILE_BUCKET_IMMUTABLE', class: 'internal', http: 500, message: 'Storage file bucket immutable.' }),
Expand Down Expand Up @@ -1584,6 +1585,7 @@ export const GENERATED_CODE_META: Record<string, GeneratedCodeMeta> = {
'STEP_UP_REQUIRED_FRESH_AUTH': { class: 'public', dynamic: false, generatedOnly: false },
'STEP_UP_REQUIRED_MFA': { class: 'public', dynamic: false, generatedOnly: false },
'STEP_UP_REQUIRED_PASSWORD': { class: 'public', dynamic: false, generatedOnly: false },
'STEP_UP_REQUIRED_PASSWORD_OR_MFA': { class: 'public', dynamic: false, generatedOnly: false },
'STORAGE_API_NOT_PROVISIONED': { class: 'public', dynamic: false, generatedOnly: false },
'STORAGE_DESTINATION_REQUIRES_TEMP': { class: 'internal', dynamic: false, generatedOnly: false },
'STORAGE_FILE_BUCKET_IMMUTABLE': { class: 'internal', dynamic: false, generatedOnly: false },
Expand Down Expand Up @@ -1665,4 +1667,4 @@ export const GENERATED_CODE_META: Record<string, GeneratedCodeMeta> = {
};

/** Total number of codes collected from constructive-db. */
export const GENERATED_CODE_COUNT = 817;
export const GENERATED_CODE_COUNT = 818;
4 changes: 2 additions & 2 deletions packages/node-type-registry/src/blueprint-types.generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ export interface DataLockParams {
/* How a guarded verb is stopped while locked. step_up requires recent strong verification (needs a provisioned user_auth_module); block refuses the verb outright with ROW_LOCKED until unlocked. */
enforcement?: 'step_up' | 'block';
/* Verification method satisfying the step-up requirement, for the guarded verbs in step_up mode and for clearing the lock */
step_up_type?: 'password' | 'mfa' | 'fresh_auth';
step_up_type?: 'password' | 'mfa' | 'fresh_auth' | 'password_or_mfa';
/* Require step-up to change the lock column itself, so a locked row cannot be quietly unlocked and then deleted. Redundant (and therefore skipped) in step_up mode when UPDATE is already guarded. */
guard_unlock?: boolean;
/* For a guarded UPDATE, restrict the guard to changes touching these columns. Empty guards the whole row. */
Expand Down Expand Up @@ -565,7 +565,7 @@ export interface EventTrackerParams {
;
/** Attaches a BEFORE trigger that calls require_step_up() to enforce recent strong verification (password, MFA, or identity-provider assertion) before allowing mutations. Requires a provisioned sessions_module (with app_settings_auth) for the target database. The step_up_window is read from app_settings_auth at runtime (default 30 minutes). Supports compound conditions (AND/OR/NOT), watch_fields (fire only when specific fields change), and simple condition_field/condition_value leaf conditions. */
export interface GuardStepUpParams {
/* Which verification method satisfies the step-up requirement (password_or_mfa is the legacy spelling of fresh_auth) */
/* Which recent proof satisfies the step-up requirement: password (password re-entry), mfa (second factor), password_or_mfa (either factor; an SSO sign-in alone does not count), or fresh_auth (any recent sign-in or re-verification, including SSO, magic link and OTP) */
step_up_type?: 'password' | 'mfa' | 'fresh_auth' | 'password_or_mfa';
/* Which DML events require step-up verification */
events?: ('INSERT' | 'UPDATE' | 'DELETE')[];
Expand Down
2 changes: 1 addition & 1 deletion packages/node-type-registry/src/data/data-lock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const DataLock: NodeTypeDefinition = {
},
step_up_type: {
type: 'string',
enum: ['password', 'mfa', 'fresh_auth'],
enum: ['password', 'mfa', 'fresh_auth', 'password_or_mfa'],
description:
'Verification method satisfying the step-up requirement, for the ' +
'guarded verbs in step_up mode and for clearing the lock',
Expand Down
6 changes: 4 additions & 2 deletions packages/node-type-registry/src/guard/step-up.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,10 @@ export const GuardStepUp: NodeTypeDefinition = {
type: 'string',
enum: ['password', 'mfa', 'fresh_auth', 'password_or_mfa'],
description:
'Which verification method satisfies the step-up requirement ' +
'(password_or_mfa is the legacy spelling of fresh_auth)',
'Which recent proof satisfies the step-up requirement: password ' +
'(password re-entry), mfa (second factor), password_or_mfa (either ' +
'factor; an SSO sign-in alone does not count), or fresh_auth (any ' +
'recent sign-in or re-verification, including SSO, magic link and OTP)',
default: 'fresh_auth',
},
events: {
Expand Down
Loading