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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion hooks/foundry-cli-guard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ fi

# Check for forbidden manual directory/file creation
FORBIDDEN_PATTERNS=(
'mkdir.*\b(api-integrations|workflows|functions|collections|ui|agents|knowledge-bases|knowledge_bases)\b'
'mkdir[^;&|]*\b(api-integrations|workflows|functions|collections|ui|agents|knowledge-bases|knowledge_bases)\b'
'touch.*manifest\.yml'
'mkdir.*\bapp\b.*&&.*touch.*manifest'
'echo.*>.*manifest\.yml'
Expand Down
2 changes: 1 addition & 1 deletion skills/api-integrations/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ python3 /path/to/foundry-skills/skills/api-integrations/scripts/adapt_spec_for_f

The helper is bundled with this skill at `scripts/adapt_spec_for_foundry.py`. Resolve that path relative to this `SKILL.md`, not the app workspace.

The script applies fixes derived from 12 production Foundry sample apps:
The script applies fixes derived from 12 Foundry sample apps:
- **Swagger 2.0 conversion**: Converts to OpenAPI 3.0 via `swagger2openapi` (npx) and writes the result next to the input as `<name>.openapi3.json` or `<name>.openapi3.yaml`. Register that file, not the original.
- **Auth fixing**: Deletes an `oauth2` scheme (and its security references) when it has `authorizationCode` and no `clientCredentials` flow; a scheme with both is kept unchanged. Adds `bearerFormat` to an `apiKey`-in-Authorization scheme when its description names the prefix (`SSWS`, `Bearer`, `Token`, `Basic`). Adds a global `security` block if missing and removes per-operation `security: []` overrides.
- **Server URLs**: Strips `https://` from variable-based URLs (Foundry adds protocol separately). Removes `default` from variables without `enum` (prevents locked dropdown).
Expand Down
2 changes: 1 addition & 1 deletion skills/api-integrations/scripts/adapt_spec_for_foundry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
adapt_spec_for_foundry.py — Transform OpenAPI specs for Falcon Foundry

Applies deterministic transformations derived from 12 production Foundry sample apps:
Applies deterministic transformations derived from 12 Foundry sample apps:
1. Swagger 2.0 conversion: Convert to OpenAPI 3.0 via swagger2openapi (npx)
2. Server URLs: Strip https:// from variable-based URLs, remove default from variables
3. Auth: Infer API key prefix via bearerFormat, remove oauth2 authorizationCode
Expand Down
2 changes: 1 addition & 1 deletion skills/workflows-development/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ foundry workflows triggers view --no-prompt # Li

### Trigger + Actions Format (standard)

This is the format produced by `foundry workflows create` and used by all production Foundry sample apps — a `trigger:` (with `next:` naming the first action) plus an `actions:` map where each action carries an `id`, `properties`, `version_constraint`, and optional `next:`, closing with `output_fields: []`. See [references/workflow-examples.md](references/workflow-examples.md#standard-trigger-actions-format) for the full canonical YAML (on-demand Okta list → print).
This is the format produced by `foundry workflows create` and used by many Foundry sample apps — a `trigger:` (with `next:` naming the first action) plus an `actions:` map where each action carries an `id`, `properties`, `version_constraint`, and optional `next:`, closing with `output_fields: []`. See [references/workflow-examples.md](references/workflow-examples.md#standard-trigger-actions-format) for the full canonical YAML (on-demand Okta list → print).

**Trigger types:**

Expand Down
4 changes: 2 additions & 2 deletions skills/workflows-development/references/workflow-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

> Parent skill: [workflows-development](../SKILL.md)

Real production examples from foundry-sample repos. All examples use the actual Fusion YAML schema: `trigger` + `actions` + optional `loops`/`conditions`.
Real examples from the foundry-sample repos. All examples use the actual Fusion YAML schema: `trigger` + `actions` + optional `loops`/`conditions`.

## Simple On-Demand Workflow

Expand Down Expand Up @@ -358,7 +358,7 @@ The `get-channel-config` function reads from the collection using the `CustomSto

## Standard trigger actions format

The format produced by `foundry workflows create`, used by all production Foundry sample apps:
The format produced by `foundry workflows create`, used by many Foundry sample apps:

```yaml
name: list-okta-users
Expand Down
12 changes: 12 additions & 0 deletions test-hooks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,18 @@ OUTPUT=$(run_hook "$GUARD" "$JSON")
assert_contains "$OUTPUT" "Manual creation" "6.6 mkdir api-integrations → advisory"
assert_not_contains "$OUTPUT" "deny" "6.6 no deny (advisory only)"

# 6.6a — mkdir of an unrelated dir chained to a command that mentions api-integrations → no output
cleanup
JSON=$(jq -n '{hook_event_name: "PreToolUse", tool_name: "Bash", tool_input: {command: "mkdir -p /tmp/okta-spec && python3 skills/api-integrations/scripts/adapt_spec_for_foundry.py /tmp/okta-spec/Okta.yaml"}}')
OUTPUT=$(run_hook "$GUARD" "$JSON")
assert_empty "$OUTPUT" "6.6a mkdir /tmp dir && script under api-integrations/ → pass"

# 6.6b — chained mkdir that does create app structure → advisory
cleanup
JSON=$(jq -n '{hook_event_name: "PreToolUse", tool_name: "Bash", tool_input: {command: "cd my-app && mkdir -p workflows"}}')
OUTPUT=$(run_hook "$GUARD" "$JSON")
assert_contains "$OUTPUT" "Manual creation" "6.6b cd && mkdir workflows → advisory"

# 6.7 — touch manifest.yml → advisory
cleanup
JSON=$(jq -n '{hook_event_name: "PreToolUse", tool_name: "Bash", tool_input: {command: "touch manifest.yml"}}')
Expand Down
4 changes: 2 additions & 2 deletions test-skill.sh
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ for m in re.finditer(r'\{[^{}]*(?:\{[^{}]*\}[^{}]*)*(?:\[[^\[\]]*(?:\[[^\[\]]*\]
# Check for manual mkdir of app structure
MANUAL_MKDIR=false
if [ -s "$TOOLS_FILE" ]; then
if grep -qE 'mkdir.*(api-integrations|workflows|functions|collections|ui/)' "$TOOLS_FILE" 2>/dev/null; then
if grep -qE 'mkdir[^;&|]*(api-integrations|workflows|functions|collections|ui/)' "$TOOLS_FILE" 2>/dev/null; then
echo " ❌ Used mkdir for app structure (should use Foundry CLI)"
MANUAL_MKDIR=true
fi
Expand Down Expand Up @@ -730,7 +730,7 @@ for i in $(seq 1 $RUNS); do
grep -qi "foundry apps init" "$TEXT_FILE" "$TOOLS_FILE" 2>/dev/null && AP_COUNT=$((AP_COUNT + 1))
grep -qi "switching.*oauth\|changed.*auth\|switch.*clientCredentials" "$TEXT_FILE" 2>/dev/null && AP_COUNT=$((AP_COUNT + 1))
grep -qi "replace.*subdomain\|replace.*your-org\|replace.*okta\.com.*with" "$TEXT_FILE" 2>/dev/null && AP_COUNT=$((AP_COUNT + 1))
grep -qE 'mkdir.*(api-integrations|workflows|functions|collections|ui/)' "$TOOLS_FILE" 2>/dev/null && AP_COUNT=$((AP_COUNT + 1))
grep -qE 'mkdir[^;&|]*(api-integrations|workflows|functions|collections|ui/)' "$TOOLS_FILE" 2>/dev/null && AP_COUNT=$((AP_COUNT + 1))
grep -qE 'touch manifest\.yml|echo.*>.*manifest\.yml|cat.*>.*manifest\.yml' "$TOOLS_FILE" 2>/dev/null && AP_COUNT=$((AP_COUNT + 1))
fi
# Count spec file reads as anti-pattern (token waste)
Expand Down
Loading