From d6d293666253758cbe73eae6e4bb2b4de7ab020e Mon Sep 17 00:00:00 2001 From: Conan Scott Date: Wed, 4 Mar 2026 10:14:40 +0000 Subject: [PATCH] Add specs/schema.md --- specs/schema.md | 169 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 specs/schema.md diff --git a/specs/schema.md b/specs/schema.md new file mode 100644 index 0000000..0b53c3e --- /dev/null +++ b/specs/schema.md @@ -0,0 +1,169 @@ +# Flow Spec Schema + +The YAML spec format for declarative ST AR flow definitions. + +## Top-Level Structure + +```yaml +version: "1.0" # Spec format version +meta: # Human-readable metadata + name: + description: +application: ... # AR Application definition +subscription: ... # Subscription definition +routes: ... # Route definitions (simple, template, composite) +prerequisites: ... # Resources that must exist before deploy +``` + +## application + +```yaml +application: + name: # AR application name (must be unique in ST) + type: AdvancedRouting # Always AdvancedRouting for AR flows +``` + +## subscription + +```yaml +subscription: + account: # ST account name that owns the subscription + folder: / # Upload folder that triggers routing (absolute path) + application: # AR application name (must match application.name) + post_transmission_actions: + ptaOnSuccessDoInAdvancedRoutingWildcardPull: true + submitFilenamePatternExpression: "*" # "*" = trigger on any file + submitFilterType: FILENAME_PATTERN + triggerFileOption: fail + triggerOnSuccessfulWildcardPull: true +``` + +Note: `submitFilenamePatternExpression` here only affects server-initiated pulls. +For client-uploaded files, use route-level `condition` to filter by file type. + +## routes.simple — Steps + +Steps are applied in array order. Each step sees all files in the route payload +unless `usePrecedingStepFiles: true` is set. + +### Compress step + +```yaml +- type: Compress + conditionType: ALWAYS # Required. ALWAYS or EL. + actionOnStepFailure: PROCEED # PROCEED = non-matching files continue + fileFilterExpression: "*.txt" # GLOB or REGEX + fileFilterExpressionType: GLOB + usePrecedingStepFiles: false # false = see all route files + singleArchiveEnabled: false # false = one ZIP per file; true = bundle all + compressionMode: ZIP # ZIP (default) or GZIP +``` + +Output filename: `.zip` + +### PgpEncryption step + +```yaml +- type: PgpEncryption + conditionType: ALWAYS + actionOnStepFailure: PROCEED + fileFilterExpression: "*.md" + fileFilterExpressionType: GLOB + usePrecedingStepFiles: false + encryptKeyExpression: # The cert name in ST cert store + encryptKeyExpressionType: ALIAS # ALIAS or EXPRESSION_WILDCARD only + encryptKeyOwnerExpression: # Account that owns the cert + encryptKeyOwnerExpressionType: NAME + compressionType: "0" # "0" = no PGP compression + useAsciiArmour: false # false = binary; true = ASCII armored + signKeyExpression: null # Optional: signing key alias + signKeyExpressionType: null + signKeyOwnerExpression: null + signKeyOwnerExpressionType: null +``` + +Output filename: `.pgp` + +**Cert requirements:** `accessLevel: PUBLIC`, `account: ` (not null). +`encryptKeyExpressionType` only accepts `ALIAS` or `EXPRESSION_WILDCARD` — not `NAME`. + +### SendToPartner step + +```yaml +- type: SendToPartner + conditionType: ALWAYS + actionOnStepFailure: FAIL + fileFilterExpression: "*" + fileFilterExpressionType: GLOB + usePrecedingStepFiles: false + partnerName: # ST partner account name + partnerSite: # ST partner site name +``` + +### ExternalScript step + +```yaml +- type: ExternalScript + conditionType: ALWAYS + actionOnStepFailure: PROCEED + fileFilterExpression: "*" + fileFilterExpressionType: GLOB + usePrecedingStepFiles: false + scriptPath: /path/to/script.sh + outputFileExpression: "${basename}.out" +``` + +## routes.template + +```yaml +template: + name: + conditionType: MATCH_ALL # Always MATCH_ALL for templates +``` + +## routes.composite + +```yaml +composite: + name: + conditionType: MATCH_ALL # Always MATCH_ALL for composites +``` + +## prerequisites + +Resources validated by `st_env_snapshot.py` before any deploy: + +```yaml +prerequisites: + accounts: + - name: + type: individual | partner + partner_accounts: + - name: + partner_sites: + - name: + partner: + certificates: + - name: + type: pgp | ssh | x509 + usage: partner | local | private + account: + accessLevel: PUBLIC | PRIVATE +``` + +If any prerequisite is missing, `st_deploy.py` exits with code 2 before making any changes. + +## EL Conditions (route-level filtering) + +To filter which files enter a route by extension: + +```yaml +routes: + simple: + conditionType: EL + condition: "${transfer.target.matches('.*\\.txt')}" +``` + +- `transfer.target` = full file path +- Use Java regex with double-escaped dot (`\\.` not `\.`) +- Single-escape throws AR0045 at runtime