# Security and Runtime Boundaries

Treat the artifact package as an untrusted application boundary with only
declared platform capabilities. A successful local build does not authorize a
cloud, database, identity, or publish operation.

## Viewer and routes

Set `viewerPolicy` to `private` or `tenant`. Route APIs under `/_artifact/*`
and call them relatively from browser code (`./_artifact/...`) so draft, live,
and immutable-version paths continue to work. Never call platform `/api/*`, use
a root-absolute artifact fetch, or add an undeclared absolute URL.

The viewer-scoped binding path is intentionally narrow: it requires a signed-in
viewer, `resource: "customers"`, and `emailField: "email"`; the runtime filters
to the matching viewer. It is not a replacement for arbitrary source ACLs.

## Data, secrets, and private state

Use catalog/read-only tools and bounded declared datasets for source data. Do
not put database URLs, source API credentials, keys, passwords, bearer tokens,
or cloud credentials in source, manifests, browser bundles, or ordinary env
variables. The app runtime must not connect directly to Postgres.

For a third-party API, declare an exact region-matching Secrets Manager ARN in
`secretBindings[]`. The runtime receives the ARN and resolves the value with
its least-privilege role (`platformSecrets.get(...)` in Node or
`get_secret(...)` in Python). Keep vendor calls server-side behind a declared
artifact route.

When a private tool needs its own durable state during authoring, use the
guarded `run_artifact_workspace_sql` namespace for that task/artifact. Source
and analytics reads remain on `run_psql`; workspace-table writes must be derived
or operator-provided and documented. Do not use it as an unscoped platform
database escape hatch.

## Webhooks and Bedrock

An ordinary private API route depends on the platform viewer/session check.
External provider webhooks are not artifact-native today: raw function URLs
require AWS IAM, stable routes authorize a viewer, required provider headers are
not a general forwarding contract, and no transactional ingress-idempotency
store is declared by the manifest. Route webhook ingestion to a reviewed
platform service; an artifact may visualize its approved status data later.

The narrow machine-ingress exception is a validated, promoted
`kind: "mcp_server"` deployment at exact `/_artifact/mcp`. It uses FastMCP
3.4.7 Streamable HTTP with stateless JSON responses. Topline creates and keeps
the bearer private, IAM-signs the Lambda request, and forwards only bounded MCP
protocol headers plus a trusted platform claim. The artifact never declares,
reads, rotates, or receives that credential. A workspace manager connects the
live artifact in Developer Access, reviews every tool, and explicitly enables
chat and/or coding agents before use.

For simple chat, use one bounded server-side Bedrock `Converse` call per turn on
a private `/_artifact/api/*` route. Use the platform-injected
`platform_artifact_inference.BedrockInference` helper and
`PLATFORM_ARTIFACT_BEDROCK_MODEL_ID`. The helper assumes the model-scoped Topline
production inference role with in-memory temporary credentials; customer data
and secret clients retain workload IAM. Customers never enable models in their
own AWS accounts. Validate/bound messages, mock the call in
local tests, and return a clear `503` if the model setting is absent. Do not
hardcode a model ID, request a Bedrock API key, put Bedrock in browser code, or
silently add tools, memory, streaming, history, or an agent loop.

## Operator boundary

The sandbox must not run direct cloud deploy, IAM, database-write, or secret
commands. Use bridge tools for the documented artifact lifecycle. If the needed
bridge capability is absent, stop and name the missing tool; do not substitute
an unapproved route.
