Skip to main content

Promotion and 4-Eyes Rule

The tk-ota-push promote command promotes an already approved and signed patch from an internal channel (such as staging or beta) to a higher channel (such as stable) without recompiling. This mechanism works hand-in-hand with the 4-eyes approval workflow (--staged / Maker-Checker).

1. The 4-Eyes Principle (--staged / Maker-Checker)​

When publishing a sensitive patch, segregation of duties between the developer submitting the fix (Maker) and the security officer or release manager authorizing it (Checker) takes place in two steps:

Inter-Track Promotion Flow
  1. Initial Submission: Developer submits the patch to an internal channel (staging) in quarantine (STAGED).
  2. Four-Eyes Review: A distinct authorized reviewer (Release Manager or Security Officer) approves the patch.
  3. Digital Signature: The patch is signed with production cryptographic credentials.
  4. Production Availability: The patch becomes active and deployable on the stable channel.

Exact Server-Side Behavior (TkushPatch Server)​

  1. Submission with --staged: the CLI sends auto_approve=false. The patch is saved with status STAGED and hashSignature = null. While STAGED, no mobile device can download it.
  2. Tenant enforceFourEyes policy: even if the developer omits --staged (auto_approve=true), if the Tenant's governance policy enforces 4-eyes review (four-eyes policy == true), the server refuses auto-approval and forces the patch into STAGED status.
  3. Approval by a second actor: when calling POST /api/admin/v1/patches/{patchId}/approve, if approvedBy equals createdBy and enforceFourEyes is enabled (or the Tenant has more than one member), the server rejects the request with HTTP 409 Conflict:
    Violation du Principe des 4 Yeux (Four-Eyes Principle) : L'approbateur (<email>) doit être différent du créateur du patch.

2. tk-ota-push promote Command​

Once a patch has been validated on staging and has reached APPROVED_AND_SIGNED status, use promote to publish it to stable:

tk-ota-push promote --patch-id <uuid> [--to-channel stable] [options]

promote Options​

Option / FlagMandatoryDefaultDescription
--patch-idYes—UUID of the source patch to promote
--to-channelNostableDestination channel (e.g., stable, beta)
--tenant-idNoshorebird.yaml / session / defaultTenant identifier
--serverNoshorebird.yaml / env / http://localhost:8080OTA server URL
--projectNo.Flutter project path (to read shorebird.yaml)
--jsonNofalseOutputs raw JSON response

3. Cryptographic Guarantees During Promotion​

When tk-ota-push promote calls POST /api/admin/v1/patches/{patchId}/promote?target_channel=<channel>, the server performs the following checks (TkushPatch Server):

  1. Status verification: the source patch must be in APPROVED_AND_SIGNED state. If it is still STAGED or ROLLED_BACK, the server returns HTTP 409 Conflict:
    Seul un patch dans l'état APPROVED_AND_SIGNED peut être promu vers un autre canal (état actuel: STAGED)
  2. Target channel verification: the destination channel must differ from the source channel, otherwise HTTP 409 Conflict is returned:
    Le canal cible (staging) est identique au canal source du patch.
  3. Binary immutability (Zero recompilation): the newly created patch on the target channel reuses the exact same differential artifact (diffArtifactPath), targetSha256Hash, and symbols file (symbolsArtifactPath).
  4. Independent sequential numbering: the server automatically computes the next sequential patchNumber on the destination channel (findMaxPatchNumberForReleaseAndChannel + 1).
  5. Per-channel signing engine re-signing: the server signs targetSha256Hash using the signing key bound to (tenantId, appId, targetChannel) and records provenance in approvedBy as PROMOTED_FROM_<SOURCE_CHANNEL>:<actor>.

Complete Workflow Example (staging to stable)​

# Step 1: Publish to staging with 4-eyes quarantine
tk-ota-push patch 1.0.0+3 -p android --channel staging --staged -m "Fix SEPA transfer"

# (After a second administrator approves the patch in the Web Console)

# Step 2: Promote to the stable production channel
tk-ota-push promote \
--patch-id 8b73f831-29cf-4cb6-8801-44ebda29910a \
--to-channel stable

Terminal output:

Promotion du patch 8b73f831-29cf-4cb6-8801-44ebda29910a vers le canal 'stable'...

✅ Patch promu avec succès !
┌──────────────────────────────────────────────────────────────────────────
│ 🚀 REÇU DE PUBLICATION PATCH OTA #2
├──────────────────────────────────────────────────────────────────────────
│ ID Patch (UUID) : c19a4502-88ef-41a0-9123-77bcde112233
│ Application & Version: sara-money-demo • v1.0.0+3
│ Cible & Canal : android (aarch64) • Canal 'stable'
│ Statut & Rollout : APPROVED_AND_SIGNED (Déploiement : 100%)
...