Skip to content

fix(safe): seed default Safe Apps so Transaction Builder appears in UI#16

Open
owenwahlgren wants to merge 1 commit intomainfrom
fix/safe-default-apps-seed
Open

fix(safe): seed default Safe Apps so Transaction Builder appears in UI#16
owenwahlgren wants to merge 1 commit intomainfrom
fix/safe-default-apps-seed

Conversation

@owenwahlgren
Copy link
Copy Markdown
Collaborator

Summary

The Transaction Builder (and other Safe Apps) were never reachable from the self-hosted Safe UI because the CFG database's safe_apps_safeapp table was never seeded. The SAFE_APPS feature flag we already set only controls whether the UI renders the Apps tab — the actual list of apps comes from database rows scoped by chain_id.

safe-config-service's initial migration creates the schema with no seed data and there are no shipped fixtures, so self-hosted deployments get an empty Apps page until rows are inserted manually through Django admin (which isn't exposed through our nginx conf).

Changes

  • ansible/roles/safe/files/init-cfg-chain.py — imports SafeApp and adds a seed_default_apps(chain_id) helper that get_or_creates three hosted apps (Transaction Builder, Drain Account, CSV Airdrop) using the Django ORM. Called on both the "chain exists" and "chain created" paths so re-running the script back-fills apps onto existing deployments.
  • kubernetes/helm/safe/templates/init-job.yaml — adds a Step 4 inside the existing CFG psycopg2 block that UPSERTs the same three app rows. Uses ON CONFLICT (url) DO UPDATE with an unnest + DISTINCT merge so the chain's ID is added to any existing row without duplicating.

Both inserts write to safe_apps_safeapp with the schema from the current safe-config-service main branch:

  • url (unique) / name / description / chain_ids (bigint[]) / listed=TRUE / featured=FALSE
  • icon_url defaults to 'safe_apps/icon_url.jpg' (the model default); UI renders a placeholder.

Apps are hosted at apps-portal.safe.global/{tx-builder,drain-safe,csv-airdrop} — we only register metadata, no self-hosting.

Test plan

  • helm lint kubernetes/helm/safe passes
  • helm template ... | ast.parse of the embedded manage.py shell Python parses cleanly
  • python3 -m py_compile ansible/roles/safe/files/init-cfg-chain.py
  • End-to-end: run make deploy-safe against a fresh L1 and verify GET /cgw/v1/chains/<id>/safe-apps returns Transaction Builder, then confirm the Apps tab in the UI renders the tile and loads the iframe
  • Idempotency: re-run the ansible play and confirm no duplicate rows / chain_id entries
  • Back-fill: run against an existing CFG DB (chain already registered) and verify Step 4 still inserts the apps

The SAFE_APPS feature flag only controls whether the UI renders the Apps
tab. The actual app list (Tx Builder, Drain Account, CSV Airdrop) comes
from safe_apps_safeapp rows scoped by chain_id. The CFG initial migration
creates the schema without any seed data, so self-hosted deployments had
an empty Apps tab and no way to reach Transaction Builder.

Seed the three hosted Safe Apps at chain init time in both paths:
- ansible/roles/safe/files/init-cfg-chain.py uses the SafeApp ORM
- kubernetes/helm/safe/templates/init-job.yaml uses an UPSERT via
  psycopg2 (consistent with the existing CFG init pattern)

Both are idempotent: re-running adds the current chain_id to existing
rows without duplicating, so existing deployments pick up Tx Builder on
the next ansible/helm apply.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant