Skip to content

Onboard a new app

Create an App CR and get a governed namespace: perimeter, quotas, and governance defaults applied by the platform, not by you. This is the manual path for app owners; the full prompt-to-running-app flow is the first governed app tutorial.

Preconditions

  • A running platform (make verify-platform green, or the local path).
  • kubectl access with permission to create apps.tendtech.io resources in tend-system.

Steps

1. Write the minimal App CR

Only the boundary tier is needed from you:

apiVersion: tendtech.io/v1alpha1
kind: App
metadata:
  name: expense-helper
  namespace: tend-system
spec:
  tier: tier1

2. Apply it

kubectl apply -f app.yaml

At admission, the app-field-defaults mutate policy fills in every governance field you left out, using the GitOps-delivered policy-defaults ConfigMap (namespace kyverno):

Field Defaulted to
spec.owner your identity (the applying user)
spec.expiry now + 90 days (defaultTTL: 2160h)
spec.dataScopes [{name: synthetic, sourceType: synthetic, access: readwrite}]
spec.resourceCaps cpu: "1", memory: "1Gi"
spec.costCap 50.00 EUR, monthly
spec.llmBudget 10.00 USD, monthly

spec.purpose is never defaulted. It stays empty until you set it, and promotion refuses without it — see Promote an app to production.

Verify it worked

kubectl get app expense-helper -n tend-system
# STATE=sandbox, OWNER=<you>, EXPIRY=<now+90d>

kubectl get app expense-helper -n tend-system \
  -o jsonpath='{.status.state} {.status.namespace}'
# sandbox tend-app-expense-helper

kubectl get app expense-helper -n tend-system \
  -o jsonpath='{range .status.conditions[*]}{.type}={.status} {end}'
# expect Ready=True and Isolated=True among the conditions

The operator has rendered the generated perimeter and caps into the app namespace — you never write these objects yourself:

kubectl get ciliumnetworkpolicies,resourcequota,limitranges \
  -n tend-app-expense-helper
# ciliumnetworkpolicy/tend-default-deny
# ciliumnetworkpolicy/tend-allow-platform-gateways
# ciliumnetworkpolicy/tend-allow-edge-ingress
# resourcequota/tend-resource-caps
# limitrange/tend-limit-defaults

Every one of them carries the provenance label tendtech.io/generated-by=tend-operator (make policy-provenance asserts this cluster-wide). Field semantics live in the App CRD reference; the perimeter shape is rendered by the operator and its decision is recorded in ADR-0007.

Getting a workload into the namespace

A bare App CR provisions a governed (empty) namespace. To also generate, build, attest, and deploy an app from a description, use the builder path:

make demo-prompt APP=expense-helper PROMPT="a form to log expenses"

It needs the builder environment set (GATEWAY_URL, OIDC_TOKEN_URL or KEYCLOAK_URL+OIDC_REALM, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET, GITEA_URL, GITEA_TOKEN) — the first governed app tutorial walks it end to end.

Troubleshooting

  • Isolated=False — the Cilium CRD is absent (for example on the GitOps-less local path). Reconciliation still progresses, but the network perimeter is not enforced there; attestation and isolation are only verified on the full stack.
  • Namespace missing — check the operator logs in tend-system; the namespace is created by the App reconciler, not by admission.