Airlock Stored Procedure Reference
Generated from the exact upstream stored procedure Markdown contract used by agents and bundled Airlock documentation.
After install or upgrade, fetch the bundled contract with CALL airlock.user.documentation();. Use CONTENT_MODE => 'PROCEDURES' for structured procedure discovery.
For agent tooling, use the public Airlock Tools repo alongside this reference.
This document defines the v1 contract for the airlock Snowflake stored procedures, covering both:
airlock.admin.*– admin‑only control plane and maintenance proceduresairlock.user.*– end‑user data access procedures
The goal is to provide a stable, predictable surface for app integrators, BI users, and tooling (e.g. Renaissance CLI).
Examples assume the installed app object is named airlock. If an account uses a different app name, substitute that name.
#Guidance for AI agents and automation
This block is for agents and integrators calling procedures from SQL (Snowsight worksheets, SnowSQL, drivers, CI, MCP tools). The same text is bundled with the Native App and returned in-SQL:
-- Default: TABLE(PAYLOAD VARIANT) — one row per heading (TOC); each PAYLOAD is structured JSON.
CALL airlock.user.documentation();
-- Full bundled markdown in one row: PAYLOAD.kind = 'full', PAYLOAD.body (UTF-8).
CALL airlock.user.documentation(CONTENT_MODE => 'FULL');
-- Procedure registry: one structured PAYLOAD row per stored-procedure signature.
CALL airlock.user.documentation(CONTENT_MODE => 'PROCEDURES');
-- Slice by numbered section ids (matches ### N. and #### N.M in the bundled doc).
CALL airlock.user.documentation('markdown', 'api_v1', 'SECTION', '4.8');
-- Chunk fallback for clients that truncate very large FULL result rows.
CALL airlock.user.documentation('markdown', 'api_v1', 'CHUNK', '1-3');
Parameters are (output_format, doc_key, content_mode, section_ids) — all optional with defaults. Default content_mode is TOC: the first PAYLOAD is kind: documentation_manifest with content_hash / etag and agent_instructions, followed by heading rows where PAYLOAD is a small object (e.g. kind: toc_entry, level, section_id, title). Every heading has a section_id: numbered headings use ids such as 4.8, while unnumbered guidance headings use stable slug ids. Use CONTENT_MODE => 'PROCEDURES' for a compact structured procedure registry: first row is kind: procedure_index_manifest, followed by kind: procedure_entry rows with procedure_name, schema_name, short_name, signature, arguments, and section_id. Use CONTENT_MODE => 'FULL' for the entire document as markdown inside PAYLOAD.body. Use CONTENT_MODE => 'SECTION' with section_ids (e.g. '3', '4.8', 'guidance-for-ai-agents-and-automation') for kind: section_bundle and a sections array of {section_id, body} objects. Use CONTENT_MODE => 'CHUNK' to receive smaller kind: "chunk" rows; section_ids may be blank for all chunks, '1', '1-3', or 'offset=0,limit=12000'.
After each app upgrade, pull the contract with CALL airlock.user.documentation(); and read PAYLOAD from each row (or use FULL / SECTION when you need prose bodies).
#Procedure mental model
Airlock procedures are meant to be guessable by family. Prefer named arguments whenever a procedure has optional parameters; positional calls are acceptable only for short discovery calls. Omit optional arguments you are not using instead of passing placeholder NULL values or typed casts. Named CALL syntax lets agents set only the fields that matter and avoids Snowflake argument-shape ambiguity.
- Discovery:
list_*,describe_*, andget_*procedures are read-only. Optional filters come after the primary object name. User-scope discovery commonly acceptsin_app_roleandinclude_managed_rolesso agents can choose an Airlock role lens without confusing it with a Snowflake role. - Declarative configuration:
create_*andalter_*admin procedures usually accept one descriptorVARIANTplusvalidate_only. Usevalidate_only, notdry_run, when validating a desired configuration without writing it. - Operational previews: destructive operational procedures use
dry_runwhen the result is a concrete preview of rows/files/events that would be changed. Drop-style configuration procedures useforcewhen the caller is overriding dependency checks. - Data submission:
validate_dataandload_datause exactly one source:pathfor an already-staged file, orfile_contentfor inline CSV. For inline loads, passfilename. For shared-folder direct writes, passpath_scope. For delegated writes, passon_behalf_of_userand let Airlock resolve the principal user's path. Do not passpath => NULL; simply omitpath. If a caller wants the file to arrive in a later workflow state such as Submitted, load first and then calledit_file_workflow; do not add workflow-state columns to the payload.load_dataevaluates active Expectations before writing the manifest row: strict unmet expectations returnEXPECTATION_BLOCKED; non-strict unmet expectations returnEXPECTATION_WARNINGwhile allowing the load. - Payload discipline: build submitted files from the spec's
column_config,file_rules, andattachment_policy. Do not invent ids or add Airlock lifecycle fields such asworkflow_status,workflow_step,approval_status,approved_by, orapproved_atunless those fields are explicitly declared by the spec as real source-system facts. Airlock returns file identity, workflow state, validation issues, and attachment status separately. - Existing-file operations: attachment and workflow procedures operate on a manifest file and therefore use
file_path/file_filenameorpath/filenameas file identity, not staged file source. - Delegation: delegation is user-to-agent authority for
airlock.user.*procedures. Delegated action procedures puton_behalf_of_useranddelegation_idat the tail. In the common case, pass onlyon_behalf_of_user; omitdelegation_idunlesslist_my_delegationsshows multiple active grants that could match. Admin procedures are not delegated. Delegated "submit" flows are still audited as load plus workflow advance, and require bothload_dataandedit_file_workflowpermission when they move past Draft. - Expectations:
descriptionshould explain the business reason in human terms.clausesencode the cadence, sequence, or interval;target_milestonenames the workflow state being expected;is_strictsays whether an unmet expectation can block workflow or load. Non-strict expectations surface as warnings/work items only. For specs without file workflow, the current file slot isActiveand the implicit upload milestone isbecame_active.effective_at/expires_atbound the lifecycle. Discovery should show both the configuration (list_expectations/describe_expectation) and operational work (list_my_expectation_work, includingDUE_ATandDAYS_UNTIL_DUE) when explaining what a person needs to do. - Returns: mutation procedures should expose structured outcomes such as
STATUS,IS_CREATED/IS_UPDATED/IS_LOADED,VALIDATION,CODE,MESSAGE, andISSUES. Agents should branch on stable fields and reason codes, then summarize prose for humans.
#What agents actually receive (no automatic “saved file”)
Snowflake returns a result set (rows/columns), not a workspace file or attachment. user.documentation does not create a .md on disk for you — anything you retrieve exists only in that query result until you copy it somewhere durable.
Expectations for agents
- Fetch — run
CALL airlock.user.documentation()(default TOC),CONTENT_MODE => 'PROCEDURES',CONTENT_MODE => 'FULL', orSECTIONwithsection_ids. - Persist — if you need a durable file, assemble from
PAYLOAD(e.g.FULL.body, or TOC/section JSON) and write to an artifact you control. SQL still does not create a file for you. - Re-read — in later turns, open that saved artifact (or call
documentationagain) instead of assuming rows still fit in context. - Avoid scraping — use
PROCEDURESfor structured procedure discovery; useSECTION, or useCHUNKand assemble rows bychunk_indexwhenFULLis too large. - Cache — store
content_hash/etagbeside the saved artifact and re-fetch when the hash changes after an app upgrade.
Do not assume a single historical CALL remains in memory across sessions, tools, or humans; treat persistence as mandatory for any long-lived automation.
#Snowflake CLI / terminal clients (optional)
With CONTENT_MODE => 'FULL', a single row can still serialize as a very wide display: many clients pad to the longest line inside the embedded markdown body. Default TOC rows carry small VARIANT objects and are easier in a terminal grid.
Practical rule: for agents using Snowflake CLI, prefer --format JSON_EXT --silent. JSON_EXT preserves VARIANT columns such as PAYLOAD, VALIDATION, and ISSUES as nested JSON objects. Plain JSON may serialize those VARIANT values as strings, and TABLE is for humans, not automation.
snow sql -c myconn --format JSON_EXT --silent \
-q "CALL airlock.user.documentation(CONTENT_MODE => 'PROCEDURES');"
For full prose, do not rely on the default ASCII table for huge markdown. Redirect with a non-grid format, or use a driver:
snowsql -c myconn -o output_format=tsv -o header=false -q "CALL airlock.user.documentation(CONTENT_MODE => 'FULL');" > airlock_api_v1.md
Other snowsql options (see Snowflake Configuring SnowSQL) include output_format=plain, csv, or friendly=false. Prefer a Snowflake driver or Snowflake CLI JSON_EXT when you want structured PAYLOAD in memory without CLI table art. Start with default CALL airlock.user.documentation() (TOC) before FULL if you only need the outline.
#Explaining next steps to a human app_admin
Admins may be unfamiliar with Airlock. When you hit limits, briefly state what you attempted, the exact procedure name, error text or reason code, and one concrete remediation (below). Separate Snowflake access / role problems from Airlock license, Airlock role, or template problems. Prefer asking the human to run a specific CALL airlock.admin.* or to use Streamlit admin flows (roles, assignments, templates, licenses) when your session is app_user only.
#Spec templates and delegated ownership (recommended automation path)
Goal: A trusted admin publishes an approved spec template (columns, file rules, workflow, optional guest model, locked fields). Automation accounts use airlock.user.create_spec_from_template instead of inventing specs ad hoc. Airlock also installs a public default_spec_draft_template so licensed app_user agents can start unpublished drafts for app_admin review without a custom template assignment.
Delegation: If the template defines template_rules.forced_owner_role (commonly app_admin for centralized ownership), an app_user caller may still instantiate the spec: assignment to the template is proof the admin delegated that shape. The merged config carries template_config.template_rules so create validates the forced owner. Without forced_owner_role, a non-admin cannot create a spec owned only by a role outside their assignment subtree—design templates explicitly for the delegation you need.
Admin setup checklist (typically once per template/automation principal):
- Ensure an Airlock role exists for the agent (e.g.
ai_agent,automation_user) viaairlock.admin.create_roles(or equivalent). - Create the template with
airlock.admin.create_spec_template(includeforced_owner_rolewhen governance requires a fixed owner). - Assign the template to that Airlock role with
airlock.admin.create_spec_template_assignment, or setis_public: truewhen every licensed app user may use the template. - Assign the Snowflake user the agent uses to that Airlock role with
airlock.admin.create_assignments(user_idis usually the Snowflake login name). - Ensure the agent holds a named license seat if it will call
airlock.user.*(get_my_license_seat,claim_license_seat()with no arguments, or admin licensing procedures).
Only app_admin maintains templates and assignments; do not widen automation to all admin.* procedures unless policy requires it.
#Chaining multiple agents (different Airlock roles)
Model multi-step pipelines with different Snowflake users or accounts, each granted APPLICATION ROLE app_user but holding different Airlock roles (core.in_app_assignments). Each step gets narrow template assignments and spec/guest access—like a business where one party submits data, another validates completeness, a third runs fraud or duplication checks, and a final stage triggers payment or downstream export.
- Airlock roles (
core.in_app_roles) are Airlock’s authorization labels;app_useris only the Snowflake procedure privilege. - Use file workflow, guest_access with isolated directories, and/or separate specs per stage so each agent sees only permitted paths (see
docs/user_access_control_model.md). - References and materialized tables can support cross-stage analytics while keeping write scope tight.
When suggesting changes, name the Airlock role, template, and assignment the admin should add or adjust.
#If the agent cannot authenticate to Snowflake
Resolve account / network / credential / role issues before debugging Airlock procedures.
| Approach | What to tell the human |
|---|---|
| SnowSQL | Install SnowSQL; add a named connection in ~/.snowsql/config (or SNOWSQL_CONFIG_FILE) with account, user, authenticator (SNOWFLAKE_JWT for key pair, OAUTH for SSO, or password where allowed), warehouse, database, schema, and a role that can use the Native App and activate app_user (or app_admin for setup). Run snowsql -c <name> -f script.sql. |
| Snowsight | Open Projects → Worksheets, use a role with access to the app, USE APPLICATION ROLE app_user or app_admin, then run the same CALL statements. |
| Drivers (Python, JDBC, etc.) | Same parameters as SnowSQL; use connection parameters documented for the Snowflake connector. |
| Key-pair authentication | Often preferred for service users: admin associates a public key with the Snowflake user; the agent loads the private key (or JWT) with no password in scripts. See Snowflake “Key-pair authentication & key-pair rotation”. |
| Programmatic access tokens (PAT) | Where enabled by account policy; time-bounded REST access—rotate and scope per security team guidance. |
SSH keys are common for git or bastion access to a runner, not a substitute for Snowflake authentication itself—pair Snowflake auth with how your runner reaches the network.
#Permission gaps: options to give the human
| Symptom | What the admin can do |
|---|---|
LICENSE_SEAT_REQUIRED / seat messages | Adjust pool / assignments via airlock.admin.* licensing procedures; or use Streamlit license management if deployed. |
| Template “not assigned to your roles” | create_spec_template_assignment linking the template to the agent’s Airlock role (not only Snowflake app_user), or mark the template is_public when it should be available to every licensed user. |
Owner / descendant_roles errors on create_spec_from_template | Template likely missing forced_owner_role while spec owner is outside the caller’s subtree; alter template or have admin create the spec; see Spec templates and delegated ownership above. |
Cannot run airlock.admin.* | Expected for dedicated automation with only app_user; human app_admin runs control-plane calls in Snowsight or SnowSQL. |
| Path / guest / workflow denials | describe_spec for permitted path_scope; consult docs/pdp_authorization_runbook.md; adjust guest_access or workflow in admin Streamlit or alter_spec. |
#1. Versioning, Security & Compatibility
- Reference version:
1.0 - Schemas:
airlock.admin– admin‑only procedures (Snowflake application roleapp_admin).airlock.user– user‑facing procedures (application rolesapp_userandapp_admin).
#1.1 Security & access model
- Airlock application roles
app_admincan call allairlock.admin.*andairlock.user.*procedures.app_usercan call onlyairlock.user.*procedures.- Snowflake object security (GRANTs on the procedures themselves) is the primary enforcement mechanism for which application role can call which schema. For file mutation/validation flows, both
airlock.user.*and keyairlock.admin.*wrappers use a shared policy decision point (PDP) for consistent in‑procedure authorization behavior and reason-code outcomes.
- Named-license gate model
airlock.user.*procedures and Streamlit usage require a named license seat (including callers withapp_admin).- Auto-assign may grant a seat on first gated call when enabled.
- License administration under
airlock.admin.*is the break-glass path and does not require the caller to already hold a seat. - Operationally, if the seat pool is full, use
CALL airlock.admin.*licensing procedures in SQL to unassign seats or raise the ceiling.
- In‑app roles and assignments
- Airlock roles (
core.in_app_roles) and assignments (core.in_app_assignments) model application‑level access on top of Snowflake roles. - User-facing procedures (
airlock.user.*) use these to enforce who can see which specs/files/history; internal checks here are about Airlock roles, not Snowflake application roles. - Admin procedures (
airlock.admin.*) may expose a lens parameter (e.g.in_app_role) so admins can “see as Airlock role X” while still relying on Snowflake’s grants for coarse‑grained admin vs user access.
- Detailed composition guide
- For the exact cascade of owner vs guest lens, role inheritance/assignment, spec state (
is_published,is_archived), path targeting, and workflow mutation checks, seedocs/user_access_control_model.md. - PDP troubleshooting and reason-code runbook:
docs/pdp_authorization_runbook.md.
- Data access philosophy
- All data access goes through narrow, purpose‑built procedures (e.g.
select_files,list_events) instead of direct table access. - Procedures are written to:
- Accept simple scalar parameters (VARCHAR, BOOLEAN, TIMESTAMP) suitable for BI tools and SQL clients.
- Enforce row‑level and object‑level access based on Airlock roles and spec configuration (e.g. guest access).
- Avoid returning sensitive data (only metadata needed for audit/observability).
- Events & observability
- Application activity is recorded in
core.eventsfrom two sources: (1) the Streamlit UI viarecord_event()inlib/utils/events.py, and (2) stored procedures that perform mutations (create/alter/drop roles, assignments, specs, retention policies; load/delete files; workflow transitions). Admin and file procedures push a row intocore.eventsafter each successful mutation, using the same event types and column semantics as the UI, so that procedure-driven changes are auditable in the same way as UI-driven changes. Events are surfaced through: airlock.admin.list_events(admin‑only) for querying events.- Higher‑level analytical helpers in
lib/utils/events.pyfor the Streamlit UI. - Event types used by procedures (aligned with UI where applicable):
USER_LOGIN,LICENSE_DENIED,LICENSE_ASSIGNED(named-license gate / self-serve seat claim),RECORD_CREATE,RECORD_IMPORT,RECORD_UPDATE,RECORD_DELETE,FILE_UPLOAD,FILE_DELETE,FILE_RETENTION_PURGE(each row removed bydelete_outdated_files;object_nameiscore.FILE_MANIFEST.pk,filenameandspec_name/pathset,upload_idinevent_description),EVENTS_AUTO_PURGE(summary after scheduled trim of oldcore.eventsrows),WORKFLOW_CHANGE(workflow step transitions fromedit_file_workflow). Event recording from procedures is best-effort (non-blocking); a failed event insert does not fail the primary operation. - The events schema is optimized for:
- Who did what (
username,in_app_role,object_name), - When (
event_timestamp), - Why (
event_type,event_description), - With optional file/spec context (
spec_name,path,filename,workflow_event).
- Retention & purging
- Retention policies (
core.retention_policies) and manifest procedures (list_outdated_files,delete_outdated_files) define - Successful
delete_outdated_filesruns (withdry_run => FALSE) emit oneFILE_RETENTION_PURGEevent per removed upload, in addition to returning one result row per file (includingmanifest_pk). - Procedures are designed to be idempotent and auditable – destructive actions (deletes, drops) are either:
- Soft‑delete first (archive/mark), or
- Guarded by explicit
forceflags and locked‑state checks.
a predictable lifecycle for spec files and their derived data.
#1.2 Compatibility rules
Within v1, non‑breaking changes (new procedures, optional parameters with safe defaults, new trailing result columns) are allowed; breaking changes (renames, parameter/type/meaning changes) are not. See the rules and versioning guidance following the procedure matrix below.
#1.3 Procedure coverage matrix (admin vs user)
The platform has two procedure categories with different trust boundaries:
airlock.admin.*for control-plane and privileged maintenance operations.airlock.user.*for assignment-scoped data operations and user workflows.
The matrix below is a role/action inventory to verify CRUD coverage and identify intentional boundaries.
| Domain | Conceptual CRUD action | Admin procedures (airlock.admin.*) | User procedures (airlock.user.*) |
|---|---|---|---|
| Roles | Create / Read / Update / Delete | create_roles, list_roles, describe_role, alter_role, drop_role | list_my_roles (read own effective roles) |
| Assignments | Create / Read / Update / Delete | create_assignments, list_assignments, describe_assignment, alter_assignment, drop_assignment | list_my_assignments (read own assignments) |
| Delegations | Create / Read / Revoke | create_delegation, list_delegations, revoke_delegation | create_delegation (self-service principal-only), list_my_delegations (read delegations involving current user) |
| Expectations | Create / Read / Update / Delete | create_expectation, list_expectations, describe_expectation, alter_expectation, drop_expectation, create_expectation_exception, alter_expectation_exception, list_expectation_exceptions, revoke_expectation_exception | list_my_expectation_work (read own actionable expectation work) |
| Specs | Create / Read / Update / Delete | create_spec, list_specs, describe_spec, get_spec, alter_spec, drop_spec | list_my_specs (read allowed specs), describe_spec (get config/fields for a spec), create_spec_from_template (scoped create path) |
| Files | Create / Read / Update / Delete | load_data, list_files, select_files, validate_data, edit_file_workflow, delete_files, list_file_versions | load_data, list_my_files, select_my_files, select_reference_data, validate_data, edit_file_workflow, delete_files |
| Attachments | Create / Read / Update / Delete | attach_to_spec, add_attachment, replace_attachment, delete_attachment | add_attachment, replace_attachment, delete_attachment |
| Spec templates | Create / Read / Update / Delete | create_spec_template, list_spec_templates, describe_spec_template, alter_spec_template, drop_spec_template, create_spec_template_assignment, list_spec_template_assignments, drop_spec_template_assignment | Used indirectly via create_spec_from_template |
| References | Create / Read / Update / Delete | register_reference, revalidate_reference, list_references, list_reference_access, grant_reference_access, revoke_reference_access, unregister_reference | No direct reference-admin procedures (intentional) |
| Retention | Create / Read / Update / Delete | create_retention_policy, list_retention_policies, describe_retention_policy, alter_retention_policy, drop_retention_policy, list_outdated_files, delete_outdated_files | No direct retention-admin procedures (intentional) |
| Events/observability | Read | list_events | No direct list_events endpoint (intentional) |
| Help / reference metadata | Read | api_info, admin_help | user_help |
Completeness check summary
- User procedure completeness: user-facing CRUD is complete for assignment-scoped file workflows, attachments, and spec discovery/history paths. Privileged setup/administration actions are intentionally excluded from user endpoints.
- Admin procedure completeness: admin coverage is complete for control-plane CRUD (roles, assignments, specs, templates, references, retention), file workflow and attachments, plus event/audit query paths.
- Boundary model: user endpoints perform in-procedure authorization checks; admin endpoints rely on stronger app-role grants plus admin-only maintenance capabilities.
Non‑breaking changes allowed in v1:
- Adding new procedures.
- Adding optional parameters with safe defaults that preserve existing behavior.
- Adding new output columns at the end of result sets (callers must be resilient to extra columns).
Breaking changes (must NOT happen in v1):
- Renaming or removing existing procedures.
- Changing parameter names, types, or required/optional semantics.
- Changing the meaning of parameters or return columns such that the same inputs produce incompatible results.
Future breaking changes must be introduced via:
- New procedures with a version suffix (e.g.
select_files_v2), or - New versioned schemas (e.g.
airlock_v2.admin,airlock_v2.user).
The current Airlock compatibility version and supported versions can be queried via:
CALL airlock.admin.api_info();
#2. Admin Schema (airlock.admin.*)
All admin procedures are callable only when the app_admin application role is active.
#2.1. Introspection & Help
airlock.admin.help(procedure_name VARCHAR DEFAULT NULL)- Description: Returns help text for admin procedures.
- Parameters:
procedure_name(optional): name of a specific procedure to describe. IfNULL, returns an overview.- Returns:
TABLE(LINE VARCHAR)– one line of help text per row. - Example:
CALL airlock.admin.help();
CALL airlock.admin.help('list_roles');
airlock.admin.api_info()- Description: Returns compatibility version metadata and procedure status.
- Returns:
API_VERSION VARCHAR– e.g.1.0SUPPORTED_VERSIONS VARCHAR– comma‑separated list, e.g.1.0PROCEDURE_NAME VARCHAR– logical name withinairlock.adminCATEGORY VARCHAR– high‑level area:introspection,roles,specs,files,history,events,retention,maintenance, orvalidationSTATUS VARCHAR–existing(others reserved for future use)NOTES VARCHAR– freeform notes (e.g.admin-only; v1 surface)- Example:
CALL airlock.admin.api_info();
#2.1.1. Named license operations
airlock.admin.list_licenses([include_inactive BOOLEAN])- Description: Lists named license holder rows and policy (same
seat_ceiling/auto_assign_enabledon every row). Default: active only (is_active = TRUE). Passinclude_inactiveTRUE to include deactivated rows (historic usernames,statusinactive).FIRST_LICENSED_AT_UTCis immutable after first assignment (proration anchor).LAST_LICENSED_AT_UTCis spell start (activated_at_utc). - Returns:
TABLE(ASSIGNED_USER, STATUS, FIRST_LICENSED_AT_UTC, LAST_LICENSED_AT_UTC, SEAT_CEILING, AUTO_ASSIGN_ENABLED) - Example:
CALL airlock.admin.list_licenses();
CALL airlock.admin.list_licenses(TRUE);
airlock.admin.get_license_ceiling()- Description: Read named-license state aligned with
set_license_ceiling: one row withseat_ceiling,auto_assign_enabled,SEATS_ASSIGNED, andSEATS_FREE. Useset_license_auto_assign(BOOLEAN)to change auto-assign. Uselist_licenses()for per-user timestamps; uselist_licenses(TRUE)to include inactive holders. - Returns:
TABLE(SEAT_CEILING, AUTO_ASSIGN_ENABLED, SEATS_ASSIGNED, SEATS_FREE) - Example:
CALL airlock.admin.get_license_ceiling();
airlock.admin.set_license_ceiling(new_ceiling NUMBER)- Description: Sets the finite license ceiling (
1to100). Decrease is blocked if active assignments exceed the new ceiling. - Returns:
TABLE(STATUS, MESSAGE) - Example:
CALL airlock.admin.set_license_ceiling(10);
airlock.admin.assign_license(user_name VARCHAR)- Description: Activates a named license for the user (
license_holders). Fails if capacity is full. - Returns:
TABLE(STATUS, MESSAGE) - Example:
CALL airlock.admin.assign_license('jane.doe');
airlock.admin.unassign_license(user_name VARCHAR)- Description: Deactivates the named license for that user (
is_active = FALSE; row andfirst_licensed_atretained). - Returns:
TABLE(STATUS, MESSAGE) - Example:
CALL airlock.admin.unassign_license('CSMITH');
airlock.admin.set_license_auto_assign(enabled BOOLEAN)- Description: Enables or disables auto-assignment for gated
user.*and Streamlit seat checks. - Returns:
TABLE(STATUS, MESSAGE) - Example:
CALL airlock.admin.set_license_auto_assign(TRUE);
#2.2. Roles & Assignments
airlock.admin.list_roles(username VARCHAR DEFAULT NULL)- Description: Lists all in‑app roles, optionally filtered by user.
- Parameters:
username(optional): return roles assigned to this user; ifNULL, return all roles.- Returns:
ROLE_NAME VARCHARDESCRIPTION VARCHARMANAGED_BY_ROLE VARCHARIS_SPEC_ADMIN BOOLEANIS_LOCKED BOOLEAN- Example:
CALL airlock.admin.list_roles();
CALL airlock.admin.list_roles('jane.doe');
airlock.admin.describe_role(role_name VARCHAR)- Description: Returns a canonical descriptor for a single in‑app role (round‑trippable for create/alter).
- Parameters:
role_name(required): in‑app role name to describe.- Returns:
ROLE_NAME VARCHARDESCRIPTION VARCHARMANAGED_BY_ROLE VARCHARIS_SPEC_ADMIN BOOLEANIS_LOCKED BOOLEAN- Example:
CALL airlock.admin.describe_role('budget_analyst');
airlock.admin.create_roles(role_descriptors VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Creates one or more in‑app roles from an array of
role_descriptorobjects. For a single role, pass a one-element array. Handles dependency resolution automatically: roles withmanaged_by_roledependencies are created in topological order (parents before children) to respect FK constraints. - Parameters:
role_descriptors(required): array of role descriptor objects, each withrole_name(required); optional:description,managed_by_role(role name or PK; must not beapp_admin—every role is managed by app_admin; omit for top-level roles),is_spec_admin,is_locked.validate_only(optional, defaultFALSE): whenTRUE, validates dependency order and returns creation plan without inserting.- Returns:
- One row per role:
ROLE_NAME VARCHAR,STATUS VARCHAR,IS_CREATED BOOLEAN,VALIDATION VARIANT. VALIDATIONis an object (not a bare boolean):outcome(created\|noop\|validate_only\|error),message, andissues(array of{ code, message, severity }, same general shape asload_dataISSUES). Idempotent re-create:outcome: "noop",IS_CREATED: FALSE, and an informational issue such asROLE_ALREADY_EXISTS. Withvalidate_only,dependency_levelis included;issuesis typically empty.- Behavior:
- Validates that all
managed_by_rolereferences are resolvable (exist in database or in the same create request). - Detects circular dependencies and returns validation errors.
- Creates roles in dependency order using topological sort (Kahn's algorithm).
- Example:
-- Single role
CALL airlock.admin.create_roles([PARSE_JSON('{"role_name": "analyst", "description": "Analyst role"}')]);
-- Multiple roles (with dependency): one PARSE_JSON per element
CALL airlock.admin.create_roles([
PARSE_JSON('{"role_name": "finadmin", "description": "Financial admin", "is_spec_admin": true}'),
PARSE_JSON('{"role_name": "budget_analyst", "description": "Budget analyst", "managed_by_role": "finadmin"}')
]);
airlock.admin.alter_role(role_name VARCHAR, role_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Alters an existing in‑app role.
role_descriptor.role_namemust matchrole_nameif set. - Parameters:
role_name(required): role to alter.role_descriptor(required): optional fieldsdescription,managed_by_role(must not beapp_admin; omit for top-level),is_spec_admin,is_locked.validate_only(optional, defaultFALSE).- Returns:
ROLE_NAME VARCHAR,STATUS VARCHAR,IS_UPDATED BOOLEAN,VALIDATION VARIANT- Example:
CALL airlock.admin.alter_role('analyst', PARSE_JSON('{"description": "Updated"}'));
airlock.admin.drop_role(role_name VARCHAR, force BOOLEAN DEFAULT FALSE)- Description: Drops an in‑app role. Role must have no assignments and no child roles. When
forceisFALSE, does not delete if role is locked. - Parameters:
role_name(required).force(optional, defaultFALSE): whenTRUE, allows drop when role is locked (dependents must still be zero).- Returns:
ROLE_NAME VARCHAR,STATUS VARCHAR,IS_DROPPED BOOLEAN,MESSAGE VARCHAR,ISSUES VARIANT– array of{code, message, severity}(same shape asload_dataISSUES); empty whenSTATUSisok/dropped.- Example:
CALL airlock.admin.drop_role('analyst');
CALL airlock.admin.drop_role('analyst', TRUE);
airlock.admin.list_assignments(username VARCHAR DEFAULT NULL, rolename VARCHAR DEFAULT NULL)- Description: Lists in‑app role assignments.
- Parameters:
username(optional): filter by user identifier.rolename(optional): filter by role name.- Returns:
ASSIGNMENT_NAME VARCHARDESCRIPTION VARCHARUSER_ID VARCHARASSIGNED_ROLE VARCHAREFFECTIVE_FROM TIMESTAMP_LTZEFFECTIVE_TO TIMESTAMP_LTZIS_LOCKED BOOLEAN- Example:
CALL airlock.admin.list_assignments();
CALL airlock.admin.list_assignments('jane.doe');
CALL airlock.admin.list_assignments(rolename => 'budget_analyst');
airlock.admin.describe_assignment(assignment_name VARCHAR)- Description: Returns a canonical descriptor for a single in‑app assignment (round‑trippable for alter).
ASSIGNED_ROLEis the role name. - Parameters:
assignment_name(required). - Returns: Same columns as list (single row or empty).
- Example:
CALL airlock.admin.describe_assignment('jane.analyst');
airlock.admin.create_assignments(assignment_descriptors VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Creates one or more in‑app role assignments from an array of
assignment_descriptorobjects. For a single assignment, pass a one-element array. Validates that allassigned_rolereferences exist before creating any assignments. Assignments don't have dependencies on each other, so all are created in parallel after validation. - Parameters:
assignment_descriptors(required): array of assignment descriptor objects, each withassignment_name,user_id,assigned_role(required); optional:description,effective_from,effective_to,is_locked.assigned_rolecan be role name or PK.validate_only(optional, defaultFALSE): whenTRUE, validates all assignments and returns validation results without inserting.- Returns:
- One row per assignment:
ASSIGNMENT_NAME VARCHAR,STATUS VARCHAR,IS_CREATED BOOLEAN,VALIDATION VARIANT - Behavior:
- Validates that all
assigned_rolereferences exist incore.in_app_roles. - Checks for duplicate
assignment_namevalues (both in input and existing). - Checks for duplicate
(user_id, assigned_role)combinations (both in input and existing). - Creates all assignments after validation passes.
- Example:
-- Single assignment: one PARSE_JSON object inside an array literal (easy to read and edit).
CALL airlock.admin.create_assignments([
PARSE_JSON('{"assignment_name": "jane.analyst", "user_id": "JANE", "assigned_role": "analyst"}')
]);
-- Multiple assignments: one PARSE_JSON per element.
CALL airlock.admin.create_assignments([
PARSE_JSON('{"assignment_name": "alice_finadmin", "user_id": "alice@example.com", "assigned_role": "finadmin"}'),
PARSE_JSON('{"assignment_name": "bob_analyst", "user_id": "bob@example.com", "assigned_role": "budget_analyst"}')
]);
-- When a field must be a SQL expression (e.g. CURRENT_USER(), timestamps), use ARRAY_CONSTRUCT(OBJECT_CONSTRUCT(...)) instead.
airlock.admin.alter_assignment(assignment_name VARCHAR, assignment_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Alters an existing assignment (description, effective_from, effective_to, is_locked only).
- Parameters:
assignment_name(required).assignment_descriptor(required): optional fieldsdescription,effective_from,effective_to,is_locked.validate_only(optional, defaultFALSE).- Returns:
ASSIGNMENT_NAME VARCHAR,STATUS VARCHAR,IS_UPDATED BOOLEAN,VALIDATION VARIANT- Example:
CALL airlock.admin.alter_assignment('jane.analyst', PARSE_JSON('{"description": "Updated", "effective_to": "2025-12-31 23:59:59"}'));
airlock.admin.drop_assignment(assignment_name VARCHAR, force BOOLEAN DEFAULT FALSE)- Description: Drops an in‑app role assignment. When
forceisFALSE, does not delete if assignment is locked. - Parameters:
assignment_name(required).force(optional, defaultFALSE): whenTRUE, allows drop when assignment is locked.- Returns:
ASSIGNMENT_NAME VARCHAR,STATUS VARCHAR,IS_DROPPED BOOLEAN,MESSAGE VARCHAR,ISSUES VARIANT– array of{code, message, severity}(same shape asload_dataISSUES); empty whenSTATUSisok/dropped.- Example:
CALL airlock.admin.drop_assignment('jane.analyst');
CALL airlock.admin.drop_assignment('jane.analyst', TRUE);
#2.3. Events
airlock.admin.list_events(username VARCHAR DEFAULT NULL, event_types VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL, event_description VARCHAR DEFAULT NULL, start_time TIMESTAMP_LTZ DEFAULT NULL, end_time TIMESTAMP_LTZ DEFAULT NULL, limit_rows INTEGER DEFAULT 200)- Description: Fetches application activity events from the internal
core.eventstable with optional filters. Admin-only. Use for auditing, BI, or dashboards. - Parameters:
username(optional): filter by username (case-insensitive exact match).event_types(optional): comma-separated list of event types (e.g.USER_LOGIN,RECORD_CREATE,FILE_UPLOAD). See event types in app.in_app_role(optional): filter by Airlock role name (case-insensitive exact match).event_description(optional): partial match on event description (case-insensitive).start_time(optional): earliestevent_timestamp(inclusive).end_time(optional): latestevent_timestamp(inclusive).limit_rows(optional, default 200): maximum rows to return; capped at 1000.- Returns:
EVENT_TIMESTAMP TIMESTAMP_LTZEVENT_TYPE VARCHAREVENT_DESCRIPTION VARCHARUSERNAME VARCHARIN_APP_ROLE VARCHAROBJECT_NAME VARCHAR– table or spec name when applicableSPEC_NAME VARCHAR– spec name when applicable (e.g. file events)- Example:
CALL airlock.admin.list_events();
CALL airlock.admin.list_events('jane.doe');
CALL airlock.admin.list_events(
event_types => 'USER_LOGIN,RECORD_CREATE',
start_time => '2024-01-01'::TIMESTAMP_LTZ,
end_time => CURRENT_TIMESTAMP(),
limit_rows => 500
);
CALL airlock.admin.list_events(in_app_role => 'spec_admin', limit_rows => 100);
#2.4. Specs & Files
airlock.admin.list_specs(in_app_role VARCHAR DEFAULT NULL)- Description: Lists all specs; supports a “lens” role for access perspective.
- Parameters:
in_app_role(optional): see specs as if you only had this role;NULL= all specs.- Returns:
SPEC_NAME VARCHARSPEC_ALIAS VARCHARDESCRIPTION VARCHAROWNER_ROLE VARCHARACCESS_TYPE VARCHAR–owner,guest, oradminGUEST_ROLE_NAME VARCHARRESTRICTED_PATH VARCHARIS_MULTI_ROLE BOOLEAN- Example:
CALL airlock.admin.list_specs();
CALL airlock.admin.list_specs('budget_analyst');
airlock.admin.describe_spec(spec_name VARCHAR)- Description: Returns a canonical descriptor for a single spec, suitable for programmatic use.
- Parameters:
spec_name(required): logical spec identifier.- Returns:
SPEC_NAME VARCHARSPEC_ALIAS VARCHARDESCRIPTION VARCHAROWNER_ROLE VARCHAR– human‑readable role nameSPEC_CONFIG VARIANT– full configuration objectIS_LOCKED BOOLEANIS_ARCHIVED BOOLEANIS_MULTI_ROLE BOOLEANIS_PUBLISHED BOOLEANIS_REFERENCE_SPEC BOOLEANACCESS_SUMMARY VARIANT– compact explanation of owner, guest, reviewer, watcher, attachment, and reference RLS policy- Example:
CALL airlock.admin.describe_spec('budget_requests');
airlock.admin.get_spec(spec_name VARCHAR)- Description: Returns the current spec configuration as VARIANT (native JSON object in the Snowflake UI), aligned with structured columns such as
load_dataISSUES. Use for round-trip editing (spool to file with SnowSQL-o output_file=config.jsonstill works) or to pass intoalter_spec/validate_specwithallow_existing_spec => TRUE. - Parameters:
spec_name(required): logical spec identifier.- Returns:
VARIANT– parsed spec_config object (NULLif the spec does not exist). - Example:
CALL airlock.admin.get_spec('budget_requests');
-- With SnowSQL to spool: snowsql -c conn -q "CALL airlock.admin.get_spec('my_spec');" -o output_file=spec.json -o header=false -o friendly=false
airlock.admin.create_spec(spec_config VARIANT, validate_only BOOLEAN DEFAULT FALSE, reuse_spec BOOLEAN DEFAULT FALSE, from_assigned_spec_template BOOLEAN DEFAULT FALSE)- Description: Creates a new spec from a canonical
spec_configpayload. This is the primary CREATE procedure for specs. - Parameters:
spec_config(required): canonical spec configuration object (same structure used byairlock.admin.validate_spec).validate_only(optional, defaultFALSE): whenTRUE, runs validation and returns the result without inserting intocore.specs.reuse_spec(optional, defaultFALSE): whenTRUE, allowsspec_nameto already exist as a directory in AIRLOCK_STAGE (e.g. after dropping the spec fromcore.specs); validation is called withreuse_spec => TRUE.from_assigned_spec_template(optional, defaultFALSE): setTRUEonly byuser.create_spec_from_template; allows delegated owner rules whentemplate_config.template_rules.forced_owner_rolematches the resolved owner.- Returns:
SPEC_NAME VARCHAR– canonical spec name that would be (or was) created.STATUS VARCHAR–okorerror.IS_CREATED BOOLEAN–TRUEonly when a new row was successfully inserted.VALIDATION VARIANT– parsed JSON result fromvalidate_spec(includingvalidand any invalid tabs/messages).- Example:
CALL airlock.admin.create_spec(PARSE_JSON('{"core_config": {"spec_name": "my_spec", "owner_role": "analyst"}}'), TRUE);
CALL airlock.admin.create_spec(:spec_config_var);
airlock.admin.import_dbt_spec_definition(dbt_payload VARIANT, overrides VARIANT DEFAULT NULL)- Description: Imports a dbt spec definition as a pending Airlock spec. Produces a draft
spec_configper the dbt→Airlock mapping and writes a row tocore.specswithimport_metadata(status=pending,pending_fields,pending_notes,source_payload). dbt models are not supported (models are DAG-based; shape comes from SQL + ancestors). Complete the spec viaairlock.admin.alter_specwith a full config (and optionally removeimport_metadata). - Parameters:
dbt_payload(required): Parsed dbt specs YAML/JSON. Accepts:{ "name", "description", "columns": [...] }, or{ "specs": [ {...} ] }(first spec used).overrides(optional):{ "owner_role", "spec_alias", "description", "is_published", "is_archived", "is_multi_role", "current_mode" }. Ifowner_roleis omitted,app_adminis used andcore_config.owner_roleis added topending_fields.- Returns:
SPEC_NAME,STATUS,IS_CREATED,DRAFT_CONFIG VARIANT,PENDING_FIELDS VARIANT,PENDING_NOTES VARIANT,VALIDATION VARIANT.- Example:
CALL airlock.admin.import_dbt_spec_definition(
PARSE_JSON('{"name":"my_spec","columns":[{"name":"id","tests":["not_null"]}]}'),
PARSE_JSON('{"owner_role":"app_admin"}')
);
airlock.admin.describe_spec_import(spec_name VARCHAR)- Description: Returns the same descriptor as
describe_specplusIMPORT_METADATA VARIANTwhen the spec was created viaimport_dbt_spec_definition. Use to inspectpending_fieldsandpending_notesbefore completing withalter_spec. - Parameters:
spec_name(required). - Returns: Same as
describe_specplusIMPORT_METADATA VARIANT(nullable).
airlock.admin.list_pending_specs()- Description: Lists specs in pending import state (
import_metadata.status=pending). - Returns:
SPEC_NAME,SPEC_ALIAS,IMPORTED_AT,PENDING_FIELDS,PENDING_NOTES.
airlock.admin.clone_spec_from_template(template_name VARCHAR, new_spec_name VARCHAR, spec_alias VARCHAR DEFAULT NULL, spec_config_overrides VARIANT DEFAULT NULL)- Description: Clones a new spec from a saved spec template. This calls
airlock.admin.create_specwith a clonedspec_config. - Parameters:
template_name(required): spec template to clone.new_spec_name(required): new spec name for the clone (canonicalized).spec_alias(optional): optional alias override for the new spec.spec_config_overrides(optional): optional overrides for editable fields (dot-path keys).- Returns:
SPEC_NAME VARCHAR– canonical spec name that would be (or was) created.STATUS VARCHAR–ok,not_found, orerror.IS_CREATED BOOLEAN–TRUEonly when a new row was successfully inserted.VALIDATION VARIANT– parsed JSON result fromvalidate_spec(includingvalidand any invalid tabs/messages).- Example:
CALL airlock.admin.clone_spec_from_template(
'finance_spec_template',
'fin_budget_requests',
spec_alias => 'FIN_Budget Requests',
spec_config_overrides => PARSE_JSON('{"core_config.description": "FY26"}')
);
airlock.admin.list_spec_templates()- Description: Lists all spec templates.
- Returns:
TEMPLATE_NAME VARCHARDESCRIPTION VARCHARIS_ACTIVE BOOLEANIS_LOCKED BOOLEANIS_PUBLIC BOOLEAN- Example:
CALL airlock.admin.list_spec_templates();
airlock.admin.describe_spec_template(template_name VARCHAR)- Description: Returns a single spec template descriptor.
- Parameters:
template_name(required): template name.- Returns:
TEMPLATE_NAME VARCHARDESCRIPTION VARCHARSPEC_CONFIG VARIANTTEMPLATE_RULES VARIANTIS_ACTIVE BOOLEANIS_LOCKED BOOLEANIS_PUBLIC BOOLEAN- Example:
CALL airlock.admin.describe_spec_template('finance_spec_template');
airlock.admin.create_spec_template(template_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Creates a new spec template.
- Parameters:
template_descriptor(required):{ template_name, description?, spec_config?, template_rules?, is_locked?, is_active?, is_public? }.is_public: truemakes the template available to every licensedapp_user.validate_only(optional, defaultFALSE): whenTRUE, validates without inserting.- Returns:
TEMPLATE_NAME VARCHARSTATUS VARCHARIS_CREATED BOOLEANVALIDATION VARIANT- Example:
CALL airlock.admin.create_spec_template(PARSE_JSON('{"template_name": "finance_spec_template"}'));
airlock.admin.alter_spec_template(template_name VARCHAR, template_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Alters an existing spec template.
- Parameters:
template_name(required): template name.template_descriptor(required):{ description?, spec_config?, template_rules?, is_locked?, is_active?, is_public? }.validate_only(optional, defaultFALSE): whenTRUE, validates without updating.- Returns:
TEMPLATE_NAME VARCHARSTATUS VARCHARIS_UPDATED BOOLEANVALIDATION VARIANT- Example:
CALL airlock.admin.alter_spec_template('finance_spec_template', PARSE_JSON('{"is_active": false}'));
airlock.admin.drop_spec_template(template_name VARCHAR, force BOOLEAN DEFAULT FALSE)- Description: Drops a spec template (blocked if locked or assigned).
- Parameters:
template_name(required): template name.force(optional, defaultFALSE): whenTRUE, allows dropping locked templates.- Returns:
TEMPLATE_NAME VARCHARSTATUS VARCHARIS_DROPPED BOOLEANMESSAGE VARCHAR- Example:
CALL airlock.admin.drop_spec_template('finance_spec_template');
airlock.admin.list_spec_template_assignments(template_name VARCHAR DEFAULT NULL)- Description: Lists spec template assignments.
- Parameters:
template_name(optional): filter by template name.- Returns:
ASSIGNMENT_NAME VARCHARTEMPLATE_NAME VARCHARASSIGNED_ROLE VARCHARASSIGNED_ROLE_NAME VARCHARDESCRIPTION VARCHAREFFECTIVE_FROM TIMESTAMP_LTZEFFECTIVE_TO TIMESTAMP_LTZIS_LOCKED BOOLEAN- Example:
CALL airlock.admin.list_spec_template_assignments();
airlock.admin.create_spec_template_assignment(assignment_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Creates a spec template assignment.
- Parameters:
assignment_descriptor(required):{ assignment_name, template_name, assigned_role, description?, effective_from?, effective_to?, is_locked? }.validate_only(optional, defaultFALSE): whenTRUE, validates without inserting.- Returns:
ASSIGNMENT_NAME VARCHARSTATUS VARCHARIS_CREATED BOOLEANVALIDATION VARIANT- Example:
CALL airlock.admin.create_spec_template_assignment(
PARSE_JSON('{"assignment_name": "fin_template_access", "template_name": "finance_spec_template", "assigned_role": "fin_analyst"}')
);
airlock.admin.drop_spec_template_assignment(assignment_name VARCHAR, force BOOLEAN DEFAULT FALSE)- Description: Drops a spec template assignment.
- Parameters:
assignment_name(required): assignment name.force(optional, defaultFALSE): whenTRUE, allows dropping locked assignments.- Returns:
ASSIGNMENT_NAME VARCHARSTATUS VARCHARIS_DROPPED BOOLEANMESSAGE VARCHAR- Example:
CALL airlock.admin.drop_spec_template_assignment('fin_template_access');
airlock.admin.alter_spec(spec_name VARCHAR, spec_config VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Alters an existing spec’s configuration using a canonical
spec_configpayload. This is the primary ALTER procedure for specs. Also used to complete a pending dbt import: fetch config via describe_spec_import or get_spec, fill required fields, optionally remove or set import_metadata.status to complete, then call alter_spec. - Parameters:
spec_name(required): logical spec identifier of the spec to update.spec_config(required): canonical spec configuration object (same structure used byairlock.admin.validate_spec). The canonicalspec_config.core_config.spec_namemust matchspec_name.validate_only(optional, defaultFALSE): whenTRUE, runs validation and returns the result without updatingcore.specs.- Returns:
SPEC_NAME VARCHAR– canonical spec name that was (or would be) updated.STATUS VARCHAR–ok,not_found, orerror.IS_UPDATED BOOLEAN–TRUEonly when an existing row was successfully updated.VALIDATION VARIANT– parsed JSON result fromvalidate_spec(includingvalidand any invalid tabs/messages, plus any additional alter-specific errors).- Example:
CALL airlock.admin.alter_spec('my_spec', :spec_config_var);
CALL airlock.admin.alter_spec('my_spec', :spec_config_var, TRUE);
airlock.admin.list_spec_versions(spec_name VARCHAR)- Description: Lists versioned spec_config metadata stored in AIRLOCK_STAGE.
- Parameters:
spec_name(required): logical spec identifier.- Returns:
SPEC_NAME VARCHARVERSION_ID VARCHARSTATUS VARCHARIS_LATEST BOOLEANSPEC_CONFIG_HASH VARCHARMETA VARIANT- Example:
CALL airlock.admin.list_spec_versions('budget_requests');
airlock.admin.get_spec_version(spec_name VARCHAR, version_id VARCHAR)- Description: Fetches a specific versioned spec_config and metadata from AIRLOCK_STAGE.
- Parameters:
spec_name(required): logical spec identifier.version_id(required): version identifier (YYYYMMDDHHMMSSorYYYYMMDDHHMMSS-<8 char uuid>).- Returns:
SPEC_NAME VARCHARVERSION_ID VARCHARSTATUS VARCHARSPEC_CONFIG VARIANTMETA VARIANT- Example:
CALL airlock.admin.get_spec_version('budget_requests', '20260315123045');
airlock.admin.backfill_spec_versions(spec_name VARCHAR DEFAULT NULL)- Description: Ensures versioned spec_config files exist in AIRLOCK_STAGE for specs in
core.specs. - Parameters:
spec_name(optional): limit to a single spec; default is all specs.- Returns:
SPEC_NAME VARCHARSTATUS VARCHARVERSION_ID VARCHARDETAILS VARIANT- Example:
CALL airlock.admin.backfill_spec_versions();
CALL airlock.admin.backfill_spec_versions('budget_requests');
airlock.admin.drop_spec(spec_name VARCHAR)- Description: Deletes the spec row from
core.specs(actual drop). Archiving a spec is done viaalter_spec(setis_archivedin spec_config). Related files in stage, manifest rows, and views are not deleted; clean them up separately if needed. - Parameters:
spec_name(required): logical spec identifier.- Returns:
SPEC_NAME VARCHARSTATUS VARCHAR–dropped,not_found, orerrorIS_DROPPED BOOLEAN–TRUEwhen the row was deletedMESSAGE VARCHAR– human‑readable description of the outcomeISSUES VARIANT– array of{code, message, severity}(same shape asload_dataISSUES); empty whenSTATUSisdropped- Example:
CALL airlock.admin.drop_spec('budget_requests');
airlock.admin.list_files(spec_name VARCHAR, in_app_role VARCHAR DEFAULT NULL)- Description: Lists files in a spec’s stage directory.
- Parameters:
spec_name(required): spec to list files from.in_app_role(optional): restrict to a specific role directory for multi‑role specs.- Returns: Snowflake
LISToutput: name VARCHARsize NUMBERmd5 VARCHARlast_modified TIMESTAMP- Example:
CALL airlock.admin.list_files('budget_requests');
CALL airlock.admin.list_files('budget_requests', 'budget_analyst');
airlock.admin.list_work_items(spec_name VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL)- Description: Lists active workflow work items across specs or one spec. Intended for dashboards and agents that need to know which files can be moved in workflow.
- Returns:
SPEC_NAME,PATH,FILENAME,WORKFLOW_STEP,WORKFLOW_STATUS,WORK_ITEM_TYPE,AVAILABLE_ACTIONS,ACCESS_REASON,TIME_IN_STATE_SECONDS,WORKFLOW_STEP_UPDATED_AT. - Example:
CALL airlock.admin.list_work_items();
CALL airlock.admin.list_work_items('budget_requests');
airlock.admin.edit_file_workflow(spec_name VARCHAR, path VARCHAR, filename VARCHAR, action VARCHAR, comment VARCHAR DEFAULT NULL, validate_only BOOLEAN DEFAULT FALSE)- Description: Moves a file’s workflow state by one step (advance/return) or archives/restores the file. Admin-only. Strict Expectations for the target workflow milestone can block the transition unless an active Exception applies.
- Parameters:
spec_name(required): logical spec identifier.path(required): scope/path of the file (e.g.defaultor role name for multi-role specs).filename(required): logical filename (no extension).action(required):advance(next step),return(previous step),archive(move to archived),restore(from archived to initial step).comment(optional): reason or note for the transition (validated for length and control characters).validate_only(optional, defaultFALSE): whenTRUE, returns validation result without updating FILE_MANIFEST.- Returns:
SPEC_NAME,PATH,FILENAME,STATUS,IS_UPDATED,VALIDATION,FROM_STEP,TO_STEP- Example:
CALL airlock.admin.edit_file_workflow('budget_requests', 'default', 'report_2025', 'advance', 'Ready for review');
CALL airlock.admin.edit_file_workflow(spec_name => 'budget_requests', path => 'finadmin', filename => 'finance', action => 'archive');
airlock.admin.select_files(spec_name VARCHAR, search_string VARCHAR DEFAULT NULL, regex_pattern VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL)- Description: Reads spec data from stage, with fuzzy or regex filename filtering.
- Parameters:
spec_name(required)search_string(optional): fuzzy match anywhere in path (preferred for most users).regex_pattern(optional): full regex; used only whensearch_stringisNULL/empty.in_app_role(optional): restrict to a role directory (multi‑role specs).- Returns:
- All configured data columns for the spec, plus:
source_filefile_last_modified- Example:
CALL airlock.admin.select_files('budget_requests');
CALL airlock.admin.select_files('budget_requests', 'report_2025');
CALL airlock.admin.select_files(spec_name => 'budget_requests', regex_pattern => '.*\\.csv\\.gz$');
CALL airlock.admin.select_files(spec_name => 'budget_requests', in_app_role => 'budget_analyst');
airlock.admin.validate_data(spec_name VARCHAR, path VARCHAR DEFAULT NULL, file_content VARCHAR DEFAULT NULL)- Description: Validates a file for a spec. Exactly one of
pathorfile_contentmust be provided. Withstaged_path: checks spec existence, non‑archived, file in app stage, CSV parseability. Withfile_content: CSV string (header + rows) passed inline; validates against speccolumn_config(columns, types, not_null, allowed_values) and FK/reference rules, including opt-in caller-scoped reference validation. For small files only. Excel vs CSV in specfile_rules.file_format.file_typeis for UI only; we never store Excel. Specs configured for Excel still accept CSV and pass validation. - Large file guidance: The Streamlit UI enforces an upload size limit for interactive use. For large files, upload directly to the stage (e.g.
PUTvia SnowSQL) and callvalidate_datawithpathinstead offile_content. - Parameters:
spec_name(required): logical spec identifier.path(optional): path to the file under the app stage (relative or with stage reference). Omit when usingfile_content.file_content(optional): CSV string (header + data rows) to validate inline. Omit when usingpath.- Returns:
SPEC_NAME VARCHARPATH VARCHAR– the path, or the logical file name (e.g.finance) whenfile_contentwas usedSTATUS VARCHAR–okorerrorIS_VALID BOOLEANISSUE_COUNT NUMBERISSUES VARIANT– array/object of structured issues.- Example:
CALL airlock.admin.validate_data('budget_requests', 'budget_requests/path/abc123/report.csv.gz');
CALL airlock.admin.validate_data(
spec_name => 'fy26_budget_requests',
file_content => 'fiscal_year,account,request,narrative\n2026,133-5111,100,Note.'
);
airlock.admin.load_data(spec_name VARCHAR, path VARCHAR DEFAULT NULL, file_content VARCHAR DEFAULT NULL, filename VARCHAR DEFAULT NULL, path_scope VARCHAR DEFAULT NULL, attachment_content_base64 VARCHAR DEFAULT NULL, attachment_filename VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL)- Description: Promotes a validated file into
core.FILE_MANIFEST(authoritative in-app table; read-only account projection isAIRLOCK_DATA.CORE.FILE_MANIFEST) for a spec. Exactly one ofpathorfile_contentmust be provided. Always validates first. Before writing the manifest row, Airlock evaluates active Expectations for the load target: workflow specs target the initial workflow step; no-workflow specs target the implicitbecame_activemilestone and display the current file asActive. A strict unmet expectation rejects the load withSTATUS = 'error',IS_LOADED = FALSE, and issue codeEXPECTATION_BLOCKED. A non-strict unmet expectation allows the load and returns issue codeEXPECTATION_WARNING. Returns spec_name, path (scope), and filename to match FILE_MANIFEST. If the spec hasmaterialize_as_table, callsadmin.sync_table(spec_name)after the manifest update. Multi-role specs require an explicit non-default scope: use a stagedpathwith a scope, or use inlinefile_contentwithpath_scope. When admin-seeding a role-isolated folder, pass the matchingin_app_roleso authorization and reference validation use the intended role lens. Optional attachment: passattachment_content_base64(+ optionalattachment_filename) to register one attachment for the loaded file in the same call. When the spec hasattachment_policy.attachment_required=true, an attachment is required in the same call: ifattachment_content_base64is omitted or empty, the load is rejected (no file is written to the manifest) and the procedure returns statuserrorwith issue codeATTACHMENT_REQUIRED. - Large file guidance: For large files, use a staged
pathinstead of inlinefile_contentto avoid UI upload limits and session memory constraints. - Parameters:
spec_name(required): logical spec identifier.path(optional): path to the file under the app stage (e.g.spec/scope/upload_id/file.csv). Omit when usingfile_content. Multi-role specs require scope in the path.file_content(optional): CSV string (header + rows) passed inline. For multi-role specs, include a non-defaultpath_scope.filename(optional): logical filename when usingfile_content.path_scope(optional): scope for inline uploads (e.g.'public/full_access').attachment_content_base64(optional): base64-encoded attachment to register for this file in the same call; required when spec hasattachment_required.attachment_filename(optional): filename for the attachment (e.g.receipt.pdf).in_app_role(optional): role lens for admin-seeded role-isolated folders and role-scoped reference validation.- Returns:
SPEC_NAME VARCHARPATH VARCHAR– scope (same as FILE_MANIFEST path)FILENAME VARCHAR– logical filename (same as FILE_MANIFEST filename)STATUS VARCHAR–okorerrorIS_LOADED BOOLEANROW_COUNT NUMBER– number of data rows loaded (nullable if unknown)ISSUE_COUNT NUMBERISSUES VARIANT– array/object of structured issues (including validation, expectation, and manifest-level problems).- Example:
CALL airlock.admin.load_data('budget_requests', 'budget_requests/scope/abc123/report.csv.gz');
CALL airlock.admin.load_data(
spec_name => 'fy26_budget_requests',
file_content => 'fiscal_year,account,request,narrative\n2026,133-5111,100,Note.',
filename => 'fy26_budget_request',
path_scope => 'finadmin',
in_app_role => 'finadmin'
);
airlock.admin.delete_files(spec_name VARCHAR, source_files VARCHAR, source_directory VARCHAR DEFAULT NULL, dry_run BOOLEAN DEFAULT FALSE)- Description: Canonical procedure to delete files from a spec: REMOVE from stage and set
removed_at/removed_byon FILE_MANIFEST. Whendry_runisTRUE, returns what would be deleted without side effects. - Parameters:
spec_name(required)source_files(required): single filename or JSON array of filenames.source_directory(optional): path/scope; if provided, only files in that path are considered.dry_run(optional, defaultFALSE).- Returns:
TABLE(SPEC_NAME, PATH, FILENAME, UPLOAD_ID, STAGE_PATH, STATUS, MESSAGE). - Example:
CALL airlock.admin.delete_files(spec_name => 'my_spec', source_files => 'report.csv.gz', dry_run => TRUE);
CALL airlock.admin.delete_files('my_spec', '["a.csv", "b.csv"]', 'finadmin', FALSE);
airlock.admin.list_file_versions(spec_name VARCHAR, source_file VARCHAR DEFAULT NULL, uploaded_after TIMESTAMP_LTZ DEFAULT NULL, uploaded_before TIMESTAMP_LTZ DEFAULT NULL)- Description: Enumerates file versions for a spec from FILE_MANIFEST.
- Parameters:
spec_name(required)source_file(optional): filter by filename (exact match).uploaded_after/uploaded_before(optional): filter onuploaded_at.- Returns:
SPEC_NAME,PATH,FILENAME,UPLOAD_ID,STAGE_PATH,IS_ACTIVE,UPLOADED_AT,UPLOADED_BY,BECAME_INACTIVE_AT,REMOVED_AT. - Example:
CALL airlock.admin.list_file_versions('my_spec');
CALL airlock.admin.list_file_versions('my_spec', 'report.csv');
CALL airlock.admin.list_file_versions(
spec_name => 'my_spec',
uploaded_after => '2024-01-01'::TIMESTAMP_LTZ,
uploaded_before => '2024-12-31'::TIMESTAMP_LTZ
);
#2.4.1. Attachment policy
Spec-level attachment policies (attachment_policy in spec config) control whether attachments are enabled, max count, active count per attachment tag, allowed types/extensions, and optional image profiles. The default active limit per attachment_tag is 1; use default_attachment_tag_limit or attachment_tag_limits to override it. When attachment_required is true, load_data (admin and user) will not accept a file upload unless an attachment is provided in the same call; the load is rejected and no file is written to the manifest (issue code ATTACHMENT_REQUIRED). Attachment metadata is stored in core.ATTACHMENT_MANIFEST; AIRLOCK_DATA.CORE.ATTACHMENT_MANIFEST is the read-only secure view for account consumers. Additional attachment behavior and Streamlit touch points: docs/attachments_batch26.md.
Preview behavior: all attachment file types are supported for storage and download. Inline preview is available for select formats only. Images and text files are previewed directly; PDFs and other binary formats are download-only.
airlock.admin.attach_to_spec(spec_name VARCHAR, attachment_stage_path VARCHAR DEFAULT NULL, attachment_content_base64 VARCHAR DEFAULT NULL, attachment_filename VARCHAR DEFAULT NULL, attachment_type VARCHAR DEFAULT 'other', description VARCHAR DEFAULT NULL, link_spec_name VARCHAR DEFAULT NULL, link_file_path VARCHAR DEFAULT NULL, link_file_filename VARCHAR DEFAULT NULL, attachment_tag VARCHAR DEFAULT NULL)- Description: Registers a binary file as a spec-level attachment (not tied to a specific data file). Use when creating a spec and its first attachment in one flow. Exactly one input mode: stage (
attachment_stage_pathunder@AIRLOCK_DATA.CORE.AIRLOCK_ATTACHMENTS) or stream (attachment_content_base64and optionalattachment_filename; decoded and uploaded via put_stream; limited by Snowflake argument size ~16 MB). Whenlink_file_*are provided, the attachment is linked to that logical file. - Parameters:
spec_name(required)attachment_stage_path(optional): path under AIRLOCK_ATTACHMENTS stage.attachment_content_base64(optional): base64-encoded content (stream mode).attachment_filename(optional): filename for stream mode.attachment_type(optional, default'other'): e.g.'other','image','document'.description(optional)link_spec_name,link_file_path,link_file_filename(optional): link attachment to this logical file.attachment_tag(optional, defaultdefault): logical attachment tag. Adding another active attachment for the same tag retires older rows beyond the tag limit.- Returns:
SPEC_NAME,ATTACHMENT_STAGE_PATH,STATUS,MESSAGE,ATTACHMENT_ID,SIZE_BYTES - Example:
CALL airlock.admin.attach_to_spec(
spec_name => 'my_spec',
attachment_content_base64 => 'YWJj',
attachment_filename => 'note.txt',
attachment_type => 'other',
description => 'Sample note'
);
airlock.admin.add_attachment(spec_name VARCHAR, file_path VARCHAR, file_filename VARCHAR, attachment_stage_path VARCHAR DEFAULT NULL, attachment_content_base64 VARCHAR DEFAULT NULL, attachment_filename VARCHAR DEFAULT NULL, attachment_type VARCHAR DEFAULT 'other', description VARCHAR DEFAULT NULL, attachment_tag VARCHAR DEFAULT NULL)- Description: Adds an attachment to an existing file in a spec. Enforces spec
attachment_policyand file workflow state (add allowed only when the file is in a step that permits file/attachment management). Exactly one ofattachment_stage_pathorattachment_content_base64(with optionalattachment_filename) is required. - Parameters:
spec_name,file_path,file_filename(required): identify the target file.attachment_stage_pathorattachment_content_base64(+ optionalattachment_filename): content source.attachment_type(optional, default'other'),description(optional),attachment_tag(optional, defaultdefault).- Returns:
SPEC_NAME,FILE_PATH,FILE_FILENAME,ATTACHMENT_ID,ATTACHMENT_STAGE_PATH,STATUS,CODE,MESSAGE,SIZE_BYTES. On denial (e.g. workflow state),STATUS='error',CODE='ACCESS_DENIED_WORKFLOW_STATE'.
airlock.admin.replace_attachment(spec_name VARCHAR, file_path VARCHAR, file_filename VARCHAR, attachment_id VARCHAR, attachment_stage_path VARCHAR DEFAULT NULL, attachment_content_base64 VARCHAR DEFAULT NULL, attachment_filename VARCHAR DEFAULT NULL, attachment_type VARCHAR DEFAULT 'other', description VARCHAR DEFAULT NULL, attachment_tag VARCHAR DEFAULT NULL)- Description: Replaces an existing attachment by
attachment_id. Same workflow and policy checks as add; same content options (stage or base64).
airlock.admin.delete_attachment(spec_name VARCHAR, file_path VARCHAR, file_filename VARCHAR, attachment_id VARCHAR)- Description: Deletes an attachment by
attachment_idfor the given file. Subject to same workflow/policy rules (manage allowed only in permitted steps).
#2.5. Retention Policies & Outdated Files
Retention policy CRUD
airlock.admin.list_retention_policies(spec_name VARCHAR DEFAULT NULL)- Description: Lists retention policies; optional filter by
spec_name(policies for that spec or account-level). - Parameters:
spec_name(optional). - Returns:
POLICY_NAME,SPEC_NAME,RETENTION_DAYS,RETENTION_MIN_VERSIONS,RETENTION_SCOPE,DESCRIPTION,IS_ACTIVE,IS_LOCKED. - Example:
CALL airlock.admin.list_retention_policies();
CALL airlock.admin.list_retention_policies('my_spec');
airlock.admin.describe_retention_policy(policy_name VARCHAR)- Description: Returns a canonical descriptor for a single retention policy (by
policy_name). - Parameters:
policy_name(required). - Returns: Same columns as list (single row or empty).
- Example:
CALL airlock.admin.describe_retention_policy('Account Default');
airlock.admin.create_retention_policy(policy_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Creates a new retention policy. Descriptor:
policy_name(required); optional:spec_name(NULL = account-level),retention_days,retention_min_versions,retention_scope,description,is_active,is_locked. Validatesretention_days/retention_min_versions>= 0 and thatspec_nameexists incore.specsif provided. - Returns:
POLICY_NAME,STATUS,IS_CREATED,VALIDATION. - Example:
CALL airlock.admin.create_retention_policy(PARSE_JSON('{"policy_name": "Spec X", "spec_name": "x", "retention_days": 30}'));
airlock.admin.alter_retention_policy(policy_name VARCHAR, policy_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Alters an existing retention policy. Optional descriptor fields:
spec_name,retention_days,retention_min_versions,retention_scope,description,is_active,is_locked. - Returns:
POLICY_NAME,STATUS,IS_UPDATED,VALIDATION. - Example:
CALL airlock.admin.alter_retention_policy('Spec X', PARSE_JSON('{"retention_days": 60}'));
airlock.admin.drop_retention_policy(policy_name VARCHAR, force BOOLEAN DEFAULT FALSE)- Description: Drops a retention policy. The account default policy cannot be dropped. When
forceisFALSE, does not delete if the policy is locked. - Parameters:
policy_name(required),force(optional, defaultFALSE). - Returns:
POLICY_NAME,STATUS,IS_DROPPED,MESSAGE. - Example:
CALL airlock.admin.drop_retention_policy('My Policy');
CALL airlock.admin.drop_retention_policy('My Policy', TRUE);
Outdated files (retention-driven purge)
airlock.admin.list_outdated_files(spec_name VARCHAR DEFAULT NULL)- Description: Lists non‑current uploads that are eligible for purge based on retention policies.
- Parameters:
spec_name(optional): limit to a specific spec.- Returns (shape may be extended in future v1.x, but these columns are stable):
spec_namepathfilenameupload_idstage_pathbecame_inactive_atuploaded_at- Example:
CALL airlock.admin.list_outdated_files();
CALL airlock.admin.list_outdated_files('sample_budget_requests');
airlock.admin.delete_outdated_files(spec_name VARCHAR DEFAULT NULL, dry_run BOOLEAN DEFAULT TRUE, limit INTEGER DEFAULT 1000)- Description: Deletes outdated files from stage and updates history, based on retention policies. When
dry_runisFALSE, writes aFILE_RETENTION_PURGErow tocore.eventsper removed file (see Events & observability above). - Parameters:
spec_name(optional): restrict scope.dry_run(optional, defaultTRUE): whenTRUE, report what would be deleted without side effects.limit(optional, default 1000): maximum number of files to delete in one call.- Returns (one row per candidate in this call; shape is stable in v1.x):
spec_name,path,filename,upload_id,stage_path,manifest_pk(core.FILE_MANIFEST.pkfor that upload row)- Example:
CALL airlock.admin.delete_outdated_files(dry_run => TRUE);
CALL airlock.admin.delete_outdated_files(dry_run => FALSE);
CALL airlock.admin.delete_outdated_files('sample_budget_requests', FALSE, 100);
#2.6. File Maintenance
airlock.admin.rebuild_file_manifest_from_stage(force BOOLEAN DEFAULT FALSE)- Description: Rebuilds
FILE_MANIFESTfrom stage listing, optionally truncating first. - Parameters:
force(optional, defaultFALSE): whenTRUE, truncates FILE_MANIFEST before rebuilding. - Returns: summary string.
- Example:
CALL airlock.admin.rebuild_file_manifest_from_stage();
CALL airlock.admin.rebuild_file_manifest_from_stage(TRUE);
airlock.admin.sync_table(spec_name VARCHAR)- Description: Syncs the materialized table for a spec with its view using MERGE. Called automatically by
load_datawhen the spec hasmaterialize_as_tableset. Admin-only; use when you need to force a sync without loading a file. - Parameters:
spec_name(required). - Returns:
STATUS,ROWS_INSERTED,ROWS_UPDATED,ROWS_DELETED,MESSAGE - Example:
CALL airlock.admin.sync_table('budget_requests');
#2.8. Spec Views & Tables
airlock.admin.rebuild_spec_view(spec_name VARCHAR)- Description: Rebuilds ACTIVE and HIST views for a single spec.
- Parameters:
spec_name(required). - Returns: summary string.
- Example:
CALL airlock.admin.rebuild_spec_view('sample_budget_requests');
airlock.admin.rebuild_spec_table(spec_name VARCHAR)- Description: Rebuilds the ACTIVE materialized table (
T_{spec_name}) for a spec and syncs it. - Parameters:
spec_name(required). - Returns: summary string.
- Example:
CALL airlock.admin.rebuild_spec_table('sample_budget_requests');
#2.9. Setup & Validation
airlock.admin.rerun_setup()- Description: Idempotent setup for core objects, baseline data, and setup‑time views.
- Returns: summary string.
- Example:
CALL airlock.admin.rerun_setup();
airlock.admin.validate_spec(spec_config VARIANT, reuse_spec BOOLEAN DEFAULT FALSE, allow_existing_spec BOOLEAN DEFAULT FALSE)- Description: Validates a
spec_configobject using the same rules as the UI: - Core config (
spec_name,spec_alias,owner_role,is_published,is_archived, workflow, etc.) - File rules (CSV/Excel)
- Column config
- Guest access, including DB checks
- Optional
rulesarray: rules may defineforeign_key,reference_map,date_window, orvariant_shapevalidation.foreign_keymay use eitherfieldor afield_pathinside a VARIANT column; see Shared schema & FK validation. - Parameters:
spec_config(required): VARIANT or JSON string.reuse_spec(optional): allow reuse of an existing spec directory in stage.allow_existing_spec(optional): allowspec_nameandspec_aliasto already exist for this same spec; use when validating a config returned byget_spec.- Returns:
- JSON string:
{"valid": true}or{"valid": false, "invalid_tabs": [...], ...}. - Example:
When allow_existing_spec is TRUE, spec_name and spec_alias may already exist for this same spec (round-trip from get_spec or alter flow).
CALL airlock.admin.validate_spec(PARSE_JSON('{"core_config": {"spec_name": "x", "owner_role": "analyst"}}'));
CALL airlock.admin.validate_spec(:config_var, reuse_spec => TRUE);
CALL airlock.admin.validate_spec(:config_var, FALSE, TRUE); -- allow_existing_spec for round-trip
#2.10. Shared schema & FK validation
These procedures support customer-defined shared views and foreign-key-like validation of spec data against those views. The schema AIRLOCK_DATA.SHARED exists in the customer's account; the app does not grant USAGE or CREATE VIEW. The customer grants those privileges (e.g. via SECURITYADMIN). See Shared schema grants.
airlock.admin.create_shared_schema()- Description: Creates the schema
AIRLOCK_DATA.SHAREDif it does not exist. Idempotent. Does not grant USAGE or CREATE VIEW; the customer performs grants (see Shared schema grants). - Parameters: None.
- Returns:
VARCHAR— summary message. - Example:
CALL airlock.admin.create_shared_schema();
airlock.admin.register_shared_view(schema_name VARCHAR, view_name VARCHAR, ref_columns VARIANT)- Description: Legacy helper that registers a view in the shared schema for use in spec FK rules. The view must already exist (created by the customer with standard SQL). Registration stores metadata in
core.shared_viewsso validation can resolve FK rules. Does not create or alter the view. New integrations should prefer unified references viaairlock.admin.register_reference. - Parameters:
schema_name(required): Short name; for MVP only'SHARED'is supported.view_name(required): Name of the view (e.g.'employees').ref_columns(required): Column name(s) that may be used as the FK target — a single VARCHAR (e.g.'email') or a JSON array (e.g.PARSE_JSON('["email","id"]')).- Returns:
TABLE(SCHEMA_NAME VARCHAR, VIEW_NAME VARCHAR, REF_COLUMNS VARIANT, STATUS VARCHAR, MESSAGE VARCHAR). - Example:
CALL airlock.admin.register_shared_view('SHARED', 'employees', PARSE_JSON('["email"]'));
airlock.admin.unregister_shared_view(schema_name VARCHAR, view_name VARCHAR)- Description: Removes the registration of a shared view. Does not drop the view itself.
- Parameters:
schema_name(required),view_name(required). - Returns:
TABLE(SCHEMA_NAME VARCHAR, VIEW_NAME VARCHAR, STATUS VARCHAR, MESSAGE VARCHAR). - Example:
CALL airlock.admin.unregister_shared_view('SHARED', 'employees');
airlock.admin.list_shared_views(schema_name VARCHAR DEFAULT NULL)(optional, legacy)- Description: Lists registered shared views.
schema_nameoptional (e.g.'SHARED');NULL= all. Superseded byairlock.admin.list_referencesfor the unified reference model. - Returns: Table of schema name, view name, ref columns, and registration metadata.
airlock.admin.register_reference(reference_name VARCHAR, ref_type VARCHAR, schema_name VARCHAR, view_name VARCHAR, spec_name VARCHAR, ref_columns VARIANT)- Description: Registers a logical FK reference backed by a shared view, a materialized ingestion spec (
spec), or a read-only reference spec (reference_spec). References are identified by a stable alias (reference_name) that specs use in FK rules (unless the rule points directly at a reference spec name; see FK rules below). - Parameters:
reference_name(required): Logical alias used in spec configs (e.g.employees_ref,ref_employees).ref_type(required):'shared_view','spec', or'reference_spec'.schema_name/view_name(forshared_view): identifyAIRLOCK_DATA.<schema_name>.<view_name>(e.g.SHARED/employees).spec_name(forspec): backing ingestion spec name; FK validation reads distinct values fromAIRLOCK_DATA.ACTIVE.T_<spec_name>.spec_name(forreference_spec): backing reference spec name (core.specswithis_reference_spec=true).view_namestores the defaultobject_keywhen the backing spec has multiplereference_config.object_paths(optional when exactly one path exists).ref_columns(required): Single FK column name (VARIANT array with one element is accepted).- Returns:
TABLE(REFERENCE_NAME VARCHAR, REF_TYPE VARCHAR, REF_COLUMNS VARIANT, STATUS VARCHAR, MESSAGE VARCHAR).
airlock.admin.revalidate_reference(reference_name VARCHAR)- Description: Smoke-check that a registered reference is still readable (
SELECT 1 … LIMIT 1). Forreference_spec, probes everyobject_pathon the backing spec. - Returns:
TABLE(REFERENCE_NAME VARCHAR, STATUS VARCHAR, MESSAGE VARCHAR).
airlock.admin.unregister_reference(reference_name VARCHAR)- Description: Removes a logical reference and any role assignments for it. Does not drop the underlying view or spec.
- Returns:
TABLE(REFERENCE_NAME VARCHAR, STATUS VARCHAR, MESSAGE VARCHAR).
airlock.admin.list_references(ref_type VARCHAR)- Description: Lists registered references.
ref_typeoptional filter ('shared_view','spec', or'reference_spec'); passNULLto list all. - Returns:
TABLE(REFERENCE_NAME, REF_TYPE, SCHEMA_NAME, VIEW_NAME, SPEC_NAME, REF_COLUMNS, REGISTERED_AT).
airlock.admin.grant_reference_access(reference_name VARCHAR, role_name_or_pk VARCHAR)- Description: Grants an Airlock role access to use a reference in FK rules.
app_adminis implicitly allowed for all references; assignments extend access to additional roles. - Returns:
TABLE(REFERENCE_NAME, ROLE_PK, ROLE_NAME, STATUS, MESSAGE).
airlock.admin.revoke_reference_access(reference_name VARCHAR, role_name_or_pk VARCHAR)- Description: Revokes an Airlock role’s access to use a reference in FK rules.
- Returns:
TABLE(REFERENCE_NAME, ROLE_PK, ROLE_NAME, STATUS, MESSAGE).
airlock.admin.list_reference_access(reference_name VARCHAR)- Description: Lists roles that have been granted access to a reference (not including the implicit
app_adminaccess). - Returns:
TABLE(REFERENCE_NAME, ROLE_PK, ROLE_NAME).
Spec config FK rule (unified): Spec config may include an optional top-level rules array. A rule with "type": "foreign_key" has either "field" (top-level column name) or "field_path" (a JSON path inside a VARIANT column), plus "ref": { "reference": "<reference_name_or_spec>", "column": "<column_name>", "object_key": "<optional>", "scope": "<optional>" }. The reference value may be:
- A
core.references.reference_name(shared_view,spec, orreference_spec), or - The
spec_nameof a reference spec (is_reference_spec=true) with no separateregister_referencerow (implicit binding).
For VARIANT payloads, use field_path:
{
"type": "foreign_key",
"field_path": {
"column": "evidence",
"json_path": "$.employee.username"
},
"ref": {
"reference": "employee_info",
"column": "employee_username"
}
}
field_path.column must be a variant column in column_config. field_path.json_path supports a small scalar path subset such as $.employee.username, $.items[0].id, or $['employee-id']. Validation parses the JSON/VARIANT cell, extracts the scalar value, and checks it against the same reference target used by normal top-level FK rules.
For flexible business payloads, use variant_shape to make a variant column first-class without freezing every future attribute as a top-level column:
{
"type": "variant_shape",
"field": "expense_details",
"allowed_root_keys": ["expense", "receipt", "allocation"],
"paths": [
{"json_path": "$.expense.business_purpose", "type": "string", "required": true},
{"json_path": "$.receipt.total", "type": "number", "required": true},
{"json_path": "$.allocation.cost_center", "type": "string", "required": false}
]
}
variant_shape.field must be a variant column. Payloads must be valid JSON objects by default. paths[].json_path uses the same simple JSON path subset as field_path; supported path types are string, integer, number, boolean, date, datetime, uuid, object, and array. allowed_root_keys is intentionally strict: when present, any undeclared root key is rejected so business-process drift is reviewed by editing the spec rule, not hidden in uploads.
When the target has multiple reference_config.object_paths, set ref.object_key to the logical key (same as for user.select_reference_data). FK validation defaults to ref.scope = "global", which runs against the full reference domain. For reference_spec targets, set ref.scope = "caller_visible" to apply that reference spec's row_filters_by_role using the caller's effective Airlock roles, ref.scope = "role_lens" to validate against the explicit in_app_role lens, or ref.scope = "username_lens" to validate against rows where reference_config.row_filter_by_username.column equals trusted CURRENT_USER(). For spec targets, scoped FK validation requires the backing spec to be materialized (core_config.materialize_as_table=true) and to define the matching read_policy.row_filters_by_role or read_policy.row_filter_by_username; Airlock applies that policy to AIRLOCK_DATA.ACTIVE.T_<spec_name> during validation.
Reference specs may omit column_config for legacy/API-minimal setups. When column_config is provided, Airlock validates it and requires every reference_config.object_paths[].readable_columns[] entry to be represented there, so the documented shape matches the selectable reference data.
- For
ref_type = 'shared_view':AIRLOCK_DATA.SHARED.<view_name>.<column>. - For
ref_type = 'spec':AIRLOCK_DATA.ACTIVE.T_<spec_name>.<column>; optional scoped validation uses the target spec'sread_policy.row_filters_by_roleorread_policy.row_filter_by_username. - For reference specs (implicit or
ref_type = 'reference_spec'): FQ object fromreference_config.object_paths.
Spec row read policy: Ingestion specs may include optional top-level read_policy.row_filters_by_role using the same vetted filter shape as reference specs, and/or read_policy.row_filter_by_username with a trusted username column. This requires core_config.materialize_as_table=true. airlock.user.select_my_files then reads from the materialized table and appends the caller's role and username predicates instead of reading raw stage files. This is the recommended model for specs such as dept_account_map, where HR should only see HR rows and finance should only see finance rows, or user-scoped maps where each caller sees only their rows.
Legacy rules using { "schema": "SHARED", "view": "<view_name>", "column": "<column_name>" } are rejected at validation time; use ref.reference + register_reference.
#3. User Schema (airlock.user.*)
User procedures are available to both app_user and app_admin application roles and are access‑controlled by in‑app roles and assignments.
#3.1. Introspection & Help
airlock.user.help(procedure_name VARCHAR DEFAULT NULL)- Description: Returns help text for user procedures.
- Parameters:
procedure_name(optional): specific procedure;NULL= overview.- Returns:
TABLE(LINE VARCHAR). - Example:
CALL airlock.user.help();
CALL airlock.user.help('list_my_specs');
airlock.user.documentation(output_format VARCHAR DEFAULT 'markdown', doc_key VARCHAR DEFAULT 'api_v1', content_mode VARCHAR DEFAULT 'TOC', section_ids VARCHAR DEFAULT NULL)- Description: Returns the bundled copy of this stored procedure reference for the installed app version as
TABLE(PAYLOAD VARIANT)— structured objects (JSON-compatible), not markdown as the column type. Defaultcontent_modeisTOC: first row iskind:documentation_manifestwithagent_instructions,content_hash, andetag, then one row per ATX heading (levels 2–6), each headingPAYLOADincluding e.g.kind:toc_entry,level,section_id,title, plusschema_version. Every TOC row has asection_id; unnumbered headings use slug ids.PROCEDURES: first row iskind:procedure_index_manifest, followed bykind:procedure_entryrows with procedure name, schema, signature, arguments, and section id.FULL: one row withkind:full,agent_instructions,suggested_filename,content_hash,etag, andbody(UTF‑8 markdown).SECTION: one row withkind:section_bundle,agent_instructions, andsections: array of{section_id, body}.CHUNK: multiple smallerkind: "chunk"rows withchunk_index,chunk_count,char_start,char_end,content_hash, andbody. - Parameters:
output_format(optional):'markdown','md', or'text'(same bundled source today).doc_key(optional): document id; only'api_v1'is supported.content_mode(optional):TOC(default),PROCEDURES,FULL,SECTION, orCHUNK(aliases accepted; case-insensitive).section_ids(optional): required forSECTION— comma‑separated TOCsection_idvalues, such as'3','4.8','3,4.8', or a slug id like'guidance-for-ai-agents-and-automation'. Optional forCHUNK— blank/all returns all chunks;'1','1-3', or'offset=0,limit=12000'selects a subset.- Returns:
TABLE(PAYLOAD VARIANT)— parse eachPAYLOADin the client; error rows usekind:errorwithcode/message. - Examples:
CALL airlock.user.documentation();
CALL airlock.user.documentation(CONTENT_MODE => 'PROCEDURES');
CALL airlock.user.documentation(CONTENT_MODE => 'FULL');
CALL airlock.user.documentation('markdown', 'api_v1', 'SECTION', '4.8');
CALL airlock.user.documentation('markdown', 'api_v1', 'CHUNK', '1-3');
#3.2. Roles & Assignments
airlock.user.list_my_roles()- Description: Lists in‑app roles available to the current user (excluding
app_admin). - Returns:
ROLE_NAME VARCHARDESCRIPTION VARCHARMANAGED_BY_ROLE VARCHARIS_SPEC_ADMIN BOOLEANIS_LOCKED BOOLEAN- Example:
CALL airlock.user.list_my_roles();
airlock.user.list_my_assignments(username VARCHAR DEFAULT NULL, rolename VARCHAR DEFAULT NULL)- Description: Lists assignments the caller can manage (their roles + child roles).
- Parameters:
username(optional): filter by user; supports comma‑separated list.rolename(optional): filter by role; supports comma‑separated list.- Returns:
ASSIGNMENT_NAME VARCHARDESCRIPTION VARCHARUSER_ID VARCHARASSIGNED_ROLE VARCHAREFFECTIVE_FROM TIMESTAMP_LTZEFFECTIVE_TO TIMESTAMP_LTZIS_LOCKED BOOLEAN- Example:
CALL airlock.user.list_my_assignments();
CALL airlock.user.list_my_assignments('jane.doe');
CALL airlock.user.list_my_assignments(rolename => 'analyst');
airlock.user.create_delegation(delegation_descriptor VARIANT, validate_only BOOLEAN DEFAULT FALSE)- Description: Creates a self-service user-to-agent delegation for
CURRENT_USER(). The caller is always the principal/on-behalf-of user. Ifdelegation_descriptor.principal_useris supplied, it must matchCURRENT_USER(). The caller must already have write access to the spec, and the spec must enabledelegation_policy. - Guardrail: Delegates cannot create second-order delegations for someone else. For example, if Deb has a grant to act for asmith, Deb cannot call this procedure to grant Charlie access for asmith.
- Admin boundary: Delegation action names are
airlock.user.*procedure actions only.airlock.admin.*procedures are never delegable throughon_behalf_of_user; admin procedures remain direct control-plane authority granted by Snowflake application role. - Runtime model: Delegations are user-level grants. A delegate's own Airlock role assignments do not expand or restrict delegated authority; Airlock re-checks the principal user's current spec access when a delegated action runs. If a delegation has
path_scope, the requested staged path or inlinepath_scopemust resolve to that same scope. - Spec policy validation:
admin.validate_specrejects invaliddelegation_policyconfig before create/edit. Policy action lists must be arrays of known delegableairlock.user.*actions; admin action names are rejected; workflow-step action lists may only narrow the global policy and must reference configured workflow steps. - Common descriptor fields:
actor_user: agent/service account user that may act.spec_name: spec where the grant applies.allowed_actions: subset allowed by the spec'sdelegation_policy, such asvalidate_data,load_data,add_attachment,replace_attachment, oredit_file_workflow. Includevalidate_datawheneverload_datais allowed, because loads validate before writing.- Optional:
delegation_id,path_scope,duration_days,comment,replace_existing. - Returns:
TABLE(DELEGATION_ID, STATUS, IS_CREATED, VALIDATION) - Example:
CALL airlock.user.create_delegation(
PARSE_JSON('{"actor_user":"deb","spec_name":"demo_employee_reimbursements","allowed_actions":["validate_data","load_data","add_attachment"],"duration_days":30}'),
FALSE
);
airlock.user.list_my_delegations(direction VARCHAR DEFAULT 'both', spec_name VARCHAR DEFAULT NULL, include_inactive BOOLEAN DEFAULT FALSE)- Description: Lists user-to-agent delegations involving
CURRENT_USER(). Usedirection => 'received'for delegations where the caller is the actor/delegate,direction => 'granted'for delegations where another actor can act for the caller, orbothfor both sides. - Parameters:
direction(optional, defaultboth):received,granted, orboth.spec_name(optional): filter to one spec.include_inactive(optional, defaultFALSE): whenFALSE, returns only currently active delegations. SetTRUEto include future, expired, or revoked delegations for acknowledgement and audit.- Returns:
DIRECTION VARCHAR,DELEGATION_ID VARCHAR,PRINCIPAL_USER VARCHAR,ACTOR_USER VARCHARACTOR_AIRLOCK_ROLE VARCHAR(legacy metadata; not authorization),SPEC_NAME VARCHAR,ALLOWED_ACTIONS VARIANTPATH_SCOPE VARCHAR,EFFECTIVE_FROM TIMESTAMP_LTZ,EFFECTIVE_TO TIMESTAMP_LTZIS_ACTIVE BOOLEAN,COMMENT VARCHAR,ACTION_CONTEXT VARIANT- Agent guidance: For rows where
DIRECTION = 'received'andIS_ACTIVE = TRUE, passPRINCIPAL_USERason_behalf_of_userto delegated user procedures such asvalidate_data,load_data,add_attachment,replace_attachment, oredit_file_workflow. For inlinevalidate_data/load_data, omitpath,in_app_role, andpath_scope; Airlock resolves the principal's folder/lens. For follow-upadd_attachmentorreplace_attachment, pass thefile_pathandfile_filenamereturned by the delegated load plus the sameon_behalf_of_user. If a follow-up delegated mutation omitson_behalf_of_user, Airlock treats it as a direct actor call and evaluates the actor's own path access. Whenload_dataincludesattachment_content_base64, that call already registers the first attachment; use a distinctattachment_tagfor extra evidence added later.replace_attachmentandedit_file_workfloware explicit actions: the specdelegation_policyand active grant must both allow them, and workflow movement must be allowed at the file's current workflow step. A delegated submit-to-Submitted experience should callload_datafirst, thenedit_file_workflow(action => 'advance')with the sameon_behalf_of_user; it should report if workflow movement is not delegated instead of trying to encode workflow state in file data. PassDELEGATION_IDasdelegation_idonly if Airlock reports an ambiguous delegation. Useinclude_inactive => TRUEonly to explain future or no-longer-effective delegations; inactive rows do not authorize work. - Demo note: After
make demo, the Deb demo user can runCALL airlock.user.list_my_delegations('received', 'demo_employee_reimbursements');and discoverdemo_delegation_deb_for_asmith_reimbursements. - Example:
CALL airlock.user.list_my_delegations('received');
CALL airlock.user.list_my_delegations('granted', 'demo_employee_reimbursements');
CALL airlock.user.list_my_delegations(direction => 'received', include_inactive => TRUE);
airlock.user.get_my_license_seat()- Description: Read-only snapshot for
CURRENT_USER: whether they hold a named license,SEAT_CEILING,AUTO_ASSIGN_ENABLED, and a shortMESSAGE. Does not claim a seat; usecheck_my_license_seat/claim_license_seat()to gate or self-assign. - Returns:
TABLE(HAS_SEAT, SEAT_CEILING, AUTO_ASSIGN_ENABLED, MESSAGE) - Example:
CALL airlock.user.get_my_license_seat();
#3.3. Specs & Files
airlock.user.list_my_specs(in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE)- Description: Lists specs accessible to the current user (owner and published guest specs).
- Parameters:
in_app_role(optional): session “lens” role; must be a role the caller holds. When set, access is evaluated for that role and roles it manages inmanaged_by_role(intersected with the caller’s assignment-derived roles), so guest specs invited to a subordinate role still appear under a manager lens. When NULL, all assignment-derived roles (including descendants) are used.include_managed_roles(optional, defaultTRUE): whenFALSE, use only the exactin_app_rolelens instead of managed descendants.- Returns:
SPEC_NAME VARCHAR,SPEC_ALIAS VARCHAR,DESCRIPTION VARCHAR,OWNER_ROLE VARCHAR,ACCESS_TYPE VARCHAR,GUEST_ROLE_NAME VARCHAR,RESTRICTED_PATH VARCHAR,IS_MULTI_ROLE BOOLEANIS_REFERENCE_SPEC BOOLEAN- Example:
CALL airlock.user.list_my_specs();
CALL airlock.user.list_my_specs('budget_analyst');
airlock.user.create_spec_from_template(template_name VARCHAR, new_spec_name VARCHAR, spec_alias VARCHAR DEFAULT NULL, spec_config_overrides VARIANT DEFAULT NULL)- Description: Creates a new spec from a spec template that is assigned to at least one of the caller’s Airlock roles (
core.spec_template_assignments) or markedis_public. Requires a named license seat like otheruser.*calls. Overrides honortemplate_rules.field_access(locked vs editable paths). When the template definestemplate_rules.forced_owner_role, new specs use that owner (e.g. centralapp_admingovernance) even though the caller could not choose that owner onairlock.admin.create_specalone—this is intentional admin-delegated behavior. The installed publicdefault_spec_draft_templateforces owner roleapp_adminand unpublished status so agents can draft specs safely for later admin publication. Ifforced_owner_roleis omitted while the template’s embedded owner is outside the caller’s assignment subtree, creation fails with an owner access error—see Guidance for AI agents and automation above. - Parameters:
template_name(required): assigned or public spec template name.new_spec_name(required): new spec name for the clone (canonicalized).spec_alias(optional): optional spec alias.spec_config_overrides(optional): overrides for editable fields (dot-path keys).- Returns:
SPEC_NAME VARCHARSTATUS VARCHARIS_CREATED BOOLEANVALIDATION VARIANT- Example:
CALL airlock.user.create_spec_from_template(
'finance_spec_template',
'fin_budget_requests',
spec_alias => 'FIN Budget Requests',
spec_config_overrides => PARSE_JSON('{"core_config.description": "FY26"}')
);
airlock.user.list_my_files(spec_name VARCHAR, in_app_role VARCHAR DEFAULT NULL)- Description: Lists files in a spec the caller can access.
- Parameters:
spec_name(required)in_app_role(optional): restrict to a role directory for multi‑role specs.- Returns: Snowflake
LISTcolumns (name,size,md5,last_modified). - Example:
CALL airlock.user.list_my_files('budget_requests');
CALL airlock.user.list_my_files('budget_requests', 'budget_analyst');
airlock.user.list_my_work_items(spec_name VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE)- Description: Lists workflow work items visible through the caller's direct Airlock roles. Agents can call this to find files to submit, review, or watch for their own role authority.
AVAILABLE_ACTIONScontains actions such asadvanceorreturnwhen the caller can move workflow; watcher rows are read-only. Delegated file submission does not by itself add principal files to this list. Delegate-only agents should uselist_my_delegationsplus delegated procedure results for on-behalf submission, andlist_my_work_itemsonly for their own direct-role work. - Returns:
SPEC_NAME,PATH,FILENAME,WORKFLOW_STEP,WORKFLOW_STATUS,WORK_ITEM_TYPE,AVAILABLE_ACTIONS,ACCESS_REASON,TIME_IN_STATE_SECONDS,WORKFLOW_STEP_UPDATED_AT. - Example:
CALL airlock.user.list_my_work_items();
CALL airlock.user.list_my_work_items('budget_requests', 'budget_reviewer', FALSE);
airlock.user.list_my_expectation_work(spec_name VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE)- Description: Lists expectation work visible to the current user.
DESCRIPTIONis the human-friendly task text admins maintain so expectation names can stay stable and compact;DETAILScarries the underlying schedule/sequence/interval evaluation. - Returns:
EXPECTATION_NAME,SPEC_NAME,DESCRIPTION,TARGET_MILESTONE,IS_STRICT,EXPECTATION_STATUS,WORK_ITEM_TYPE,DUE_AT,DAYS_UNTIL_DUE,MATCHING_FILE_COUNT,ACTIVE_EXCEPTION_COUNT,DETAILS. - Example:
CALL airlock.user.list_my_expectation_work();
CALL airlock.user.list_my_expectation_work('budget_requests');
- Cross-spec source references (immutable lineage)
Admins declare allowed downstream→upstream pairs with airlock.admin.create_spec_source_link (optional link_options: required_workflow_status, max_count, upload flags) and can revoke policy with airlock.admin.disable_spec_source_link. Users list eligible upstream files with airlock.user.list_eligible_source_files, pin rows with airlock.user.add_file_reference, remove pins with airlock.user.remove_file_reference, and inspect pins with airlock.user.list_file_references (pass a file_manifest_pk that appears on either side of the reference).
airlock.user.describe_spec(spec_name VARCHAR, in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE)- Description: Returns a safe descriptor for a spec the caller can access: column_config (field names, types, tests such as
not_null), file_rules (file format, delimiters, etc.), attachment_policy (attachments enabled, max count, allowed extensions, required), minimal core_config / file_workflow (step names and reviewer actions), ACCESSIBLE_PATHS (array of{path_scope, access_level}), and ACCESS_SUMMARY (owner, guest, reviewer, watcher, attachment, and reference RLS explanation). Only paths this caller may use are included (other guests and their paths are not shown). Use ACCESSIBLE_PATHS to choose thepath_scopeto pass toload_data(e.g.public/full_accessfor write,public/read_accessfor read-only). Watcher roles get read-only visibility for matching path/workflow-state filters. Access is enforced; returns no row if the caller has no access. - Parameters:
spec_name(required)in_app_role(optional): lens role for multi‑role specs.include_managed_roles(optional, defaultTRUE): whenFALSE, use only the exactin_app_rolelens instead of managed descendants.- Returns: One row:
SPEC_NAME,SPEC_ALIAS,DESCRIPTION,CORE_CONFIG(VARIANT),COLUMN_CONFIG(VARIANT),FILE_RULES(VARIANT),ATTACHMENT_POLICY(VARIANT),FILE_WORKFLOW(VARIANT),ACCESSIBLE_PATHS(VARIANT array of{path_scope, access_level}). - Example:
CALL airlock.user.describe_spec('incoming_line_items');
CALL airlock.user.describe_spec('incoming_line_items', 'automation_user'); -- ACCESSIBLE_PATHS shows e.g. [{"path_scope": "public/full_access", "access_level": "full_access"}]
airlock.user.validate_data(spec_name VARCHAR, path VARCHAR DEFAULT NULL, file_content VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL, path_scope VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE, on_behalf_of_user VARCHAR DEFAULT NULL, delegation_id VARCHAR DEFAULT NULL)- Description: Validates a file for a spec using assignment-based authorization. Same semantics as
airlock.admin.validate_data; caller must have write access to the spec/path (owner or guest with write on that path). Exactly one ofpath(staged file) orfile_content(inline CSV string) required. Prefer named arguments. For normal delegated inline validation, passfile_contentandon_behalf_of_user; Airlock resolves the principal user's folder/lens and matching delegation. If role-lens FK/reference rules require an explicit role, pass the principal's Airlock role asin_app_role; Airlock checks it against the principal's assignments, not the actor's. Usedelegation_idonly if more than one active grant matches. Inline CSV validation includes FK/reference rules. Direct calls use the caller's Airlock role context; delegated calls use the principal user's resolved lens. - Returns:
SPEC_NAME,PATH,STATUS,IS_VALID,ISSUE_COUNT,ISSUES(VARIANT). Delegation denials returnSTATUS = 'error'with oneISSUESentry whosecodeis a stable delegation code such asDELEGATION_NOT_FOUND,DELEGATION_ACTION_NOT_ALLOWED, orINVALID_DELEGATION_POLICY. - Example:
CALL airlock.user.validate_data(
spec_name => 'incoming_line_items',
file_content => 'record_id,category,attachment_filename\nINV-2025-001,operations,invoice_scan.pdf',
in_app_role => 'automation_user',
path_scope => 'public/full_access'
);
airlock.user.load_data(spec_name VARCHAR, path VARCHAR DEFAULT NULL, file_content VARCHAR DEFAULT NULL, filename VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL, path_scope VARCHAR DEFAULT NULL, attachment_content_base64 VARCHAR DEFAULT NULL, attachment_filename VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE, on_behalf_of_user VARCHAR DEFAULT NULL, delegation_id VARCHAR DEFAULT NULL)- Description: Loads a file for a spec using assignment-based authorization. Same semantics as
airlock.admin.load_data; caller must have write access to the spec/path. Exactly one ofpath(staged file) orfile_content(inline CSV) required. Prefer named arguments. For normal delegated inline loads, passfile_content,filename, any attachment fields, andon_behalf_of_user; Airlock resolves the principal user's folder/lens and matching delegation. If validation needs a role-lens FK/reference check, pass the principal's Airlock role asin_app_role. Usedelegation_idonly if more than one active grant matches. For non-delegated guest-enabled specs with shared folders, passpath_scope(e.g.'public/full_access','public/append_access') when needed to disambiguate the target scope shown bydescribe_spec. Active Expectations are evaluated before the manifest row is written. Strict unmet expectations reject the load withEXPECTATION_BLOCKED; non-strict unmet expectations returnEXPECTATION_WARNINGbut still load. For no-workflow specs, the load target isbecame_activeand the visible current state isActive. Optional attachment: passattachment_content_base64(+ optionalattachment_filename) to register one attachment for the loaded file in the same call. If you later calladd_attachmentfor the same file, use the returnedPATH/FILENAMEand a distinctattachment_tagfor extra evidence. When the spec hasattachment_policy.attachment_required=true, an attachment is required in the same call: ifattachment_content_base64is omitted or empty, the load is rejected (no file is written to the manifest) and the procedure returns statuserrorwith issue codeATTACHMENT_REQUIRED. - Returns:
SPEC_NAME,PATH,FILENAME,STATUS,IS_LOADED,ROW_COUNT,ISSUE_COUNT,ISSUES. Delegation denials returnSTATUS = 'error'with oneISSUESentry whosecodeis a stable delegation code. Expectation findings useEXPECTATION_BLOCKEDfor strict failures andEXPECTATION_WARNINGfor non-strict warnings. - Example (create file and attach in one call):
CALL airlock.user.load_data(
spec_name => 'incoming_line_items',
file_content => 'record_id,category,attachment_filename\nINV-2025-001,operations,invoice_scan.pdf',
filename => 'INV-2025-001',
in_app_role => 'automation_user',
path_scope => 'public/full_access',
attachment_content_base64 => '<base64_encoded_image>',
attachment_filename => 'invoice_scan.pdf'
);
airlock.user.select_my_files(spec_name VARCHAR, search_string VARCHAR DEFAULT NULL, regex_pattern VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL)- Description: Reads spec data the caller can access, with the same fuzzy/regex semantics as
airlock.admin.select_files. For specs withread_policy.row_filters_by_roleorread_policy.row_filter_by_username, reads fromAIRLOCK_DATA.ACTIVE.T_<spec_name>and applies the caller's effective-role and/or username row filters; raw stage reads are not used for those row-filtered specs. - Parameters:
spec_name(required)search_string(optional): fuzzy match in pathregex_pattern(optional): full regex whensearch_stringis NULL/emptyin_app_role(optional): restrict to a role directory- Returns: Same as
airlock.admin.select_files(configured data columns plussource_file,file_last_modified). - Example:
CALL airlock.user.select_my_files('budget_requests');
CALL airlock.user.select_my_files('budget_requests', 'report_2025');
CALL airlock.user.select_my_files(spec_name => 'budget_requests', in_app_role => 'budget_analyst');
airlock.user.select_reference_data(spec_name VARCHAR, object_key VARCHAR, row_limit NUMBER DEFAULT 500, in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE, row_offset NUMBER DEFAULT 0, record_reference_read_event BOOLEAN DEFAULT TRUE)- Description: Governed
SELECTagainst a read-only reference spec (core_config.is_reference_spec). Resolves access likedescribe_spec, then readsreference_config.object_pathsforobject_key(FQdatabase_name.schema_name.object_name). Optionalreference_config.row_filters_by_roleappends vettedANDpredicates for the caller’s effective Airlock roles; optionalreference_config.row_filter_by_usernameappends a trustedCURRENT_USER()predicate.row_limitdefaults to 500 (max 5000);row_offsetdefaults to 0 (max 100000) forLIMIT/OFFSETpagination. Whenrecord_reference_read_eventisTRUE(default), inserts a best-effortREFERENCE_READrow intocore.events. Whenreadable_columnsis set on the object path, only those columns are selected; otherwiseSELECT *; if the reference spec also providescolumn_config, those readable columns must be documented there. The account must grant the applicationSELECTon the underlying object. - Returns:
TABLE()— dynamic columns from the target object. - Example:
CALL airlock.user.select_reference_data('finance_ref', 'gl_entries');
CALL airlock.user.select_reference_data(
spec_name => 'finance_ref',
object_key => 'gl_entries',
row_limit => 100,
in_app_role => 'budget_analyst'
);
CALL airlock.user.select_reference_data(
spec_name => 'finance_ref',
object_key => 'gl_entries',
row_limit => 100,
in_app_role => 'budget_analyst',
row_offset => 100,
record_reference_read_event => FALSE
);
airlock.user.edit_file_workflow(spec_name VARCHAR, path VARCHAR, filename VARCHAR, action VARCHAR, comment VARCHAR DEFAULT NULL, validate_only BOOLEAN DEFAULT FALSE, in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE, on_behalf_of_user VARCHAR DEFAULT NULL, delegation_id VARCHAR DEFAULT NULL)- Description: Moves file workflow state for files the caller can access. Same actions as
airlock.admin.edit_file_workflow(advance,return,archive,restore). Direct calls use the caller's Airlock role and assignment/workflow permissions (owner or guest with manage permission in the current step). Delegated calls passon_behalf_of_user; Airlock checks the active delegation, principal access, target file path, workflow step policy, and the principal's workflow PDP. The specdelegation_policyand active grant must both allowedit_file_workflowat the current workflow step. Strict Expectations for the target workflow milestone can block the transition unless an active Exception applies. - Parameters:
spec_name,path,filename,action(required);comment(optional);validate_only(optional, defaultFALSE).in_app_role(optional): lens role; must be in caller’s effective roles; whenNULL, current context role is used.- Returns: Same as admin
edit_file_workflow:SPEC_NAME,PATH,FILENAME,STATUS,IS_UPDATED,VALIDATION,FROM_STEP,TO_STEP. Delegation denials returnSTATUS = 'error'with a stable delegation code inVALIDATION.issues[0].code. - Example:
CALL airlock.user.edit_file_workflow('budget_requests', 'default', 'report_2025', 'advance', 'Ready for review');
CALL airlock.user.edit_file_workflow(spec_name => 'timesheets', path => 'joe', filename => 'joe_2026_05_17', action => 'advance', comment => 'Submitted by agent', on_behalf_of_user => 'joe');
airlock.user.add_attachment(spec_name VARCHAR, file_path VARCHAR, file_filename VARCHAR, attachment_stage_path VARCHAR DEFAULT NULL, attachment_content_base64 VARCHAR DEFAULT NULL, attachment_filename VARCHAR DEFAULT NULL, attachment_type VARCHAR DEFAULT 'other', description VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE, attachment_tag VARCHAR DEFAULT NULL, on_behalf_of_user VARCHAR DEFAULT NULL, delegation_id VARCHAR DEFAULT NULL)- Description: Adds an attachment to an existing file. Same semantics as
airlock.admin.add_attachmentwith in-procedure authorization (caller must have access to the spec/file and the file must be in a workflow step that allows attachment management). Exactly one ofattachment_stage_pathorattachment_content_base64(+ optionalattachment_filename) required. For delegated follow-up attachments, passon_behalf_of_user; Airlock checks the active delegation, principal access, target file path, and workflow step. Ifon_behalf_of_useris omitted, the call is direct actor work and can correctly fail whenfile_pathbelongs to the principal's isolated folder. Usedelegation_idonly if more than one active grant matches. - Guest roles (e.g.
automation_user): The procedure is granted toapp_user. A user who only has guest access to a spec (e.g. assigned roleautomation_userwithfull_accesson the spec’spublic/full_accessfolder) can attach files to existing files in that path by calling this procedure with the samefile_path/file_filename. Passin_app_role => 'automation_user'(or the guest role name) so the PDP evaluates access under that role; the file path must be under a directory where that guest has write/update (e.g.public/full_access). For delegated calls, omitin_app_roleunless selecting the principal's role lens; delegation never uses the actor's role to expand the principal's authority. - Returns:
SPEC_NAME,FILE_PATH,FILE_FILENAME,ATTACHMENT_ID,ATTACHMENT_STAGE_PATH,STATUS,CODE,MESSAGE,SIZE_BYTES. On workflow denial,CODE='ACCESS_DENIED_WORKFLOW_STATE'; on delegation denial,CODEis the stable delegation code. - Example (guest role attaching to an existing file):
-- Guest role with write on public/full_access attaches supporting evidence to an existing row file.
CALL airlock.user.add_attachment(
spec_name => 'incoming_line_items',
file_path => 'public/full_access',
file_filename => 'INV-2025-001',
attachment_content_base64 => '<base64_encoded_image>',
attachment_filename => 'invoice_scan.pdf',
attachment_type => 'other',
description => 'Supporting scan',
in_app_role => 'automation_user'
);
CALL airlock.user.add_attachment(
spec_name => 'demo_employee_reimbursements',
file_path => 'asmith',
file_filename => 'rb_asmith_001',
attachment_content_base64 => '<base64_encoded_image>',
attachment_filename => 'receipt.png',
on_behalf_of_user => 'asmith'
);
airlock.user.replace_attachment(spec_name VARCHAR, file_path VARCHAR, file_filename VARCHAR, attachment_id VARCHAR, attachment_stage_path VARCHAR DEFAULT NULL, attachment_content_base64 VARCHAR DEFAULT NULL, attachment_filename VARCHAR DEFAULT NULL, attachment_type VARCHAR DEFAULT 'other', description VARCHAR DEFAULT NULL, in_app_role VARCHAR DEFAULT NULL, include_managed_roles BOOLEAN DEFAULT TRUE, attachment_tag VARCHAR DEFAULT NULL, on_behalf_of_user VARCHAR DEFAULT NULL, delegation_id VARCHAR DEFAULT NULL)- Description: Replaces an attachment by
attachment_id; same content options as admin (stage or base64). Optionalin_app_rolelens. Subject to same workflow and access checks as add. For delegated replacement, passon_behalf_of_user; Airlock checks the active delegation, principal access, target file path, workflow step, and requiresreplace_attachmentin both the specdelegation_policyand the active grant. Usedelegation_idonly if more than one active grant matches. Replacement is permanent in Airlock, so grant it only for specs where corrected evidence replacement is part of the business process. - Returns:
SPEC_NAME,FILE_PATH,FILE_FILENAME,ATTACHMENT_ID,ATTACHMENT_STAGE_PATH,STATUS,CODE,MESSAGE,SIZE_BYTES. On delegation denial,CODEis the stable delegation code.
airlock.user.delete_attachment(spec_name VARCHAR, file_path VARCHAR, file_filename VARCHAR, attachment_id VARCHAR)- Description: Deletes an attachment by
attachment_idfor the given file; subject to same workflow/access rules as add/replace. This is a direct-role destructive action, not an on-behalf-of delegation surface in the current contract.
#4. Common Workflows
#4.1 Manage in‑app roles and assignments (admin + user)
- Goal: Define application roles and assign users to them, then let users see their own roles/assignments.
- Typical admin flow:
-- Create a new role (one JSON object per array element)
CALL airlock.admin.create_roles([
PARSE_JSON('{
"role_name": "budget_analyst",
"description": "Can view and manage budget specs",
"is_spec_admin": true
}')
]);
-- Assign a user to the role (same style as create_assignments)
CALL airlock.admin.create_assignments([
PARSE_JSON('{
"assignment_name": "jane.budget_analyst",
"user_id": "JANE",
"assigned_role": "budget_analyst"
}')
]);
-- Inspect roles/assignments (admin)
CALL airlock.admin.list_roles();
CALL airlock.admin.list_assignments('JANE');
- Typical user flow:
-- See which Airlock roles you have
CALL airlock.user.list_my_roles();
-- See which assignments you can manage
CALL airlock.user.list_my_assignments();
#4.2 Spec lifecycle: from config to current data
- Goal: Create or update a spec, validate a staged file, load it, and inspect current versions.
- Admin flow:
-- Validate a spec config (without changing data)
CALL airlock.admin.validate_spec(:spec_config_json);
-- Create a new spec (or alter an existing one)
CALL airlock.admin.create_spec(:spec_config_json);
-- or
CALL airlock.admin.alter_spec('budget_requests', :spec_config_json);
-- Validate a staged file for the spec
CALL airlock.admin.validate_data(
'budget_requests',
'budget_requests/path/abc123/report_2025.csv.gz'
);
-- Load the validated file into FILE_MANIFEST
CALL airlock.admin.load_data(
'budget_requests',
'budget_requests/path/abc123/report_2025.csv.gz'
);
-- Inspect active file versions
CALL airlock.admin.list_file_versions('budget_requests');
- User‑side access:
-- List specs you can see
CALL airlock.user.list_my_specs();
-- List files you can see for a spec
CALL airlock.user.list_my_files('budget_requests');
-- Read current data for a spec you can access
CALL airlock.user.select_my_files('budget_requests');
#4.3 Retention and purge (outdated files)
- Goal: Configure retention for a spec and safely purge outdated files.
- Admin flow:
-- Create or update a retention policy for a spec
CALL airlock.admin.create_retention_policy(PARSE_JSON('{
"policy_name": "Budget Retention",
"spec_name": "budget_requests",
"retention_days": 365,
"retention_min_versions": 2,
"retention_scope": "non_current"
}'));
-- Preview which files are eligible for purge
CALL airlock.admin.list_outdated_files('budget_requests');
-- Dry-run delete to see what WOULD be removed
CALL airlock.admin.delete_outdated_files('budget_requests', dry_run => TRUE, limit => 100);
-- Commit delete (REMOVE from stage + mark history)
CALL airlock.admin.delete_outdated_files('budget_requests', dry_run => FALSE, limit => 100);
-- Audit retention removals (see FILE_RETENTION_PURGE in list_events event_types)
CALL airlock.admin.list_events(event_types => 'FILE_RETENTION_PURGE', limit_rows => 200);
#4.4 Auditing activity and history
- Goal: Inspect application activity and historical changes to spec data.
- Admin activity audit:
-- Recent events
CALL airlock.admin.list_events();
-- Events for a specific user
CALL airlock.admin.list_events('jane.doe');
-- Events for a specific Airlock role in a time window
CALL airlock.admin.list_events(
event_types => 'FILE_UPLOAD,FILE_DELETE,FILE_RETENTION_PURGE',
in_app_role => 'budget_analyst',
start_time => '2025-01-01'::TIMESTAMP_LTZ,
end_time => CURRENT_TIMESTAMP(),
limit_rows => 500
);
#4.5. Shared view and FK validation
- Goal: Define a shared view (e.g. employees), register it, and create a spec whose column values must match that view (e.g. email_address must exist in employees.email).
- Prerequisite: Customer has granted USAGE and CREATE VIEW on
AIRLOCK_DATA.SHAREDto the role that will create views (see Shared schema grants). - Admin flow:
-- 1) Create shared schema if needed (idempotent)
CALL airlock.admin.create_shared_schema();
-- 2) Customer creates the view (standard SQL; role must have CREATE VIEW on AIRLOCK_DATA.SHARED)
CREATE OR REPLACE VIEW AIRLOCK_DATA.SHARED.employees AS
SELECT id, name, email FROM my_db.my_schema.employee_source;
-- 3) Register the view so Airlock can use it in FK rules
CALL airlock.admin.register_shared_view('SHARED', 'employees', PARSE_JSON('["email"]'));
-- 4) Create (or alter) a spec with a FK rule in spec_config.rules
CALL airlock.admin.create_spec(PARSE_JSON('{
"core_config": {"spec_name": "contacts_shared_fk", "owner_role": "app_admin", ...},
"column_config": [
{"name": "full_name", "type": "string", "tests": ["not_null"], "description": ""},
{"name": "email_address", "type": "string", "tests": ["not_null", "foreign_key"], "description": ""}
],
"rules": [{"type": "foreign_key", "field": "email_address", "ref": {"schema": "SHARED", "view": "employees", "column": "email"}}],
"file_rules": { ... },
"guest_access": { ... },
"sample_data": { ... }
}'));
-- 5) Validate and load files (FK validation runs; invalid rows are reported and blocked)
CALL airlock.admin.validate_data('contacts_shared_fk', 'path/to/file.csv.gz');
CALL airlock.admin.load_data('contacts_shared_fk', 'path/to/file.csv.gz');
#4.6. File workflow and attachments
- Goal: Move files through workflow steps (advance/return/archive/restore) and attach files to specs or to specific data files.
- File workflow (specs with
file_workflow: true):
-- Admin: move file to next step
CALL airlock.admin.edit_file_workflow('budget_requests', 'default', 'report_2025', 'advance', 'Ready for review');
-- User: same, with Airlock role context
CALL airlock.user.edit_file_workflow('budget_requests', 'default', 'report_2025', 'advance', 'Ready for review');
- Attachments (specs with
attachment_policy.attachments_enabled): add/replace/delete are allowed only when the file is in a workflow step that permits file/attachment management.attachment_tagidentifies the logical attachment tag and defaults todefaultwith one active row. On denial, procedures returnCODE='ACCESS_DENIED_WORKFLOW_STATE'.
-- Admin: spec-level attachment (e.g. when creating spec + first attachment)
CALL airlock.admin.attach_to_spec(
spec_name => 'my_spec',
attachment_content_base64 => 'YWJj',
attachment_filename => 'note.txt',
attachment_type => 'other',
description => 'Sample'
);
-- Admin or user: add attachment to an existing file (path/scope + filename)
CALL airlock.admin.add_attachment(
spec_name => 'my_spec',
file_path => 'default',
file_filename => 'finance',
attachment_content_base64 => 'base64...',
attachment_filename => 'receipt.pdf',
attachment_type => 'document',
description => 'Q1 receipt',
attachment_tag => 'receipt'
);
CALL airlock.user.add_attachment(
spec_name => 'my_spec',
file_path => 'default',
file_filename => 'finance',
attachment_content_base64 => 'base64...',
attachment_filename => 'receipt.pdf',
attachment_type => 'other',
description => 'Receipt',
in_app_role => 'my_role',
attachment_tag => 'receipt'
);
#4.7. User: create a file and attach a file
- Goal: As an app user (or an AI agent acting as that user), create a new data file in a spec and optionally attach a binary (e.g. CSV row + PDF receipt) in the same call or in a follow-up call. This is the typical flow for line-of-business submissions where evidence is attached to a logical record.
- Prerequisites: Caller has access to the spec (owner or guest). For guest access on a spec with a shared folder, the caller must use
path_scope(e.g.'public/full_access') when loading the file. Calldescribe_spec(spec_name, in_app_role, include_managed_roles)and use the ACCESSIBLE_PATHS array to see whichpath_scopevalues you may use and their access level (e.g.public/full_accessfor write); only your paths are listed, not other guests. - One-call option (recommended when the spec has
attachment_required)
Pass attachment_content_base64 and optional attachment_filename to load_data so the file and attachment are registered in one procedure call. When the spec has attachment_policy.attachment_required=true, you must provide the attachment in this call; otherwise the load is rejected and no file is uploaded (procedure returns status error, issue code ATTACHMENT_REQUIRED).
CALL airlock.user.describe_spec('incoming_line_items', 'automation_user', TRUE);
CALL airlock.user.validate_data(
spec_name => 'incoming_line_items',
file_content => 'record_id,category,attachment_filename\nINV-2025-001,operations,invoice_scan.pdf',
in_app_role => 'automation_user',
path_scope => 'public/full_access'
);
CALL airlock.user.load_data(
spec_name => 'incoming_line_items',
file_content => 'record_id,category,attachment_filename\nINV-2025-001,operations,invoice_scan.pdf',
filename => 'INV-2025-001',
in_app_role => 'automation_user',
path_scope => 'public/full_access',
attachment_content_base64 => '<base64_encoded_image>',
attachment_filename => 'invoice_scan.pdf'
);
- Two-step option (load then attach in a second call):
- Describe the spec → Validate → Load (without attachment params).
- Attach with
add_attachment(spec_name, file_path, file_filename, ...)using the samePATHandFILENAMEreturned byload_data.
- Reimbursements (CSV + receipt image/PDF) same pattern: use
load_datawithattachment_content_base64(andattachment_filename) in the same call, or load thenadd_attachmentwith the samefile_path/file_filename. - Submit-to-workflow option: If the business action means "submit for review", first load the clean business payload, then call
edit_file_workflow(action => 'advance')to move the returnedPATH/FILENAMEto Submitted. For delegated submissions, pass the sameon_behalf_of_userto both calls and requireedit_file_workflowin both the spec delegation policy and active grant. Reviewer pushback should return the file to Draft with a workflow comment; the principal then sees the item in My Work and can resubmit before any expectation due date.
#4.8. AI and agent integration
- Goal: Integrate AI assistants or automation so they can submit data and files into Snowflake through Airlock without direct stage or broad write privileges. See Product intent in
docs/product_intent.mdfor the vision (receipts, budget drafts, etc.). - Procedure surface for agents (all under
airlock.user.*, granted toapp_user): - Discovery:
list_my_roles(),list_my_specs(in_app_role, include_managed_roles),describe_spec(spec_name, in_app_role, include_managed_roles)to learn schema, required fields, and attachment rules. - Delegation discovery:
list_my_delegations('received')to learn active grants where the agent may act for another user; passinclude_inactive => TRUEonly when explaining future, expired, or revoked grants. - Create file (and optional attachment in one call):
validate_data(...)thenload_data(..., path_scope, attachment_content_base64, attachment_filename). When the spec hasattachment_required, pass the attachment in this call or the load fails. For delegated inline loads, omitpath_scopeunless deliberately targeting a non-default shared scope; Airlock resolves the principal's folder. - Submit for review: after a successful load, call
edit_file_workflow(..., action => 'advance')to reach Submitted only when workflow policy allows it. For delegated work, keep passingon_behalf_of_user; if the grant does not include workflow movement, report the loaded Draft file instead. - Attach to file (if not done in
load_data, or for additional evidence):add_attachment(spec_name => ..., file_path => ..., file_filename => ..., attachment_content_base64 => ..., attachment_filename => ..., attachment_tag => ...);file_path/file_filenamemust match the loaded file. For delegated follow-up evidence, also passon_behalf_of_user; use a distinctattachment_tagwhen the originalload_dataalready attached the default evidence. - Read:
list_my_files(spec_name),select_my_files(spec_name); for reference specs,select_reference_data(spec_name, object_key, ...). - Authorization: Procedures enforce Airlock roles and assignments; guest roles (e.g.
automation_user) only see and write to specs/paths they are granted (e.g.public/full_access). Passin_app_rolewhen the user has multiple roles so the PDP evaluates under the correct lens.
#5. Where to Go Next
- For examples and usage patterns, see:
- Streamlit code under
src/airlock/streamlit/lib/** - Tests under
tests/airlock/app_setup_scripts/procedures/scripts/
This document should be kept in sync with:
src/airlock/app_setup_scripts/procedures/**(SQL procedure definitions)src/airlock/app_setup_scripts/procedures/scripts/**(Python handlers)src/airlock/app_setup_scripts/procedures/scripts/admin_help.py(admin help text)src/airlock/app_setup_scripts/procedures/scripts/user_help.py(user help text)docs/attachments_batch26.md(attachment policy companion; Streamlit behavior)