Skip to content

Keep Shopify operations truthful and releases recoverable - #214

Merged
OziinG merged 25 commits into
mainfrom
codex/cc-265-shopify-deploy-hardening
Aug 24, 2026
Merged

Keep Shopify operations truthful and releases recoverable#214
OziinG merged 25 commits into
mainfrom
codex/cc-265-shopify-deploy-hardening

Conversation

@OziinG

@OziinG OziinG commented Aug 24, 2026

Copy link
Copy Markdown
Contributor

Change control: EVNSolution/clever-change-control#265

Outcome

  • makes order and compliance webhook admission session-free, bounded, HMAC-authenticated, and dependent on a durable Server receipt
  • renders operational facts as independent Pills with directional gaps and honest unknown states
  • adds target-scoped locking, immutable releases, verified SQLite snapshots, exact-image rollback, atomic pointers, and safe pruning for production/K-food deployments

Verification

  • App full serial: 624 passed
  • Root full serial: 603 passed
  • Deploy hostile/runtime: 24 passed
  • Build, typecheck, lint, public URL guard, actionlint, shellcheck, YAML and diff checks: passed
  • Independent deploy review and verification: approved

Rollout

Manual workflow dispatch for production and kfood after merge; exact prior image and database rollback evidence must be recorded.

OziinG added 21 commits August 24, 2026 22:12
Validate the untouched raw body with Shopify's supported webhook primitive, require a durable Delivery API receipt before acknowledgement, and expose sanitized token health for operators.

Constraint: K-food rollout must remain fail-closed and preserve Shopify retry semantics.

Rejected: authenticate.webhook for order admission | pinned 1.2.1 source performs offline-session validation after HMAC.

Confidence: high

Scope-risk: moderate

Directive: Keep Delivery API as the final HMAC and durable-inbox authority; retry mode must never acknowledge.

Tested: clean npm ci; pinned integrity/source SHA verification; 563 app tests; lint; typecheck; build; public URL guard; three compose configs.

Not-tested: live K-food webhook delivery and production metrics are deployment-stage gates.
Reject non-POST admission explicitly and retain the last token failure across later successful syncs so operators can query historical failure evidence.

Constraint: Health evidence must stay sanitized and must not alter Shopify SDK internals.

Confidence: high

Scope-risk: narrow

Directive: Do not clear lastFailureAt or lastErrorCode when current token sync returns healthy.

Tested: 564 app tests; targeted webhook/token tests; lint; typecheck; build.

Not-tested: live K-food traffic remains the deployment-stage gate.
Constraint: Preserve G006 session-free webhook and token-health behavior while consuming the additive server operationalState contract without per-row requests.
Rejected: Keep bespoke status badges or infer device progress from GPS | Independent source authority and accessible Pill semantics require one shared pure mapper.
Confidence: high
Scope-risk: moderate
Directive: Keep RouteOperationalStateV1 additive and render absent evidence as Unknown; do not reintroduce prose-separated operational summaries.
Tested: app 571 tests; lint; production build; typecheck; public URL guard; main/dev/kfood compose config
Not-tested: authenticated browser visual smoke and production deployment
Constraint: Group children are rebuilt from routeGroups while operationalState is enriched on the already fetched routePlans list.
Rejected: Fetch operational state per grouped row | It adds N+1 requests and duplicates the server batch contract.
Confidence: high
Scope-risk: narrow
Directive: Preserve the routePlanId join whenever grouped child presentation is rebuilt; never derive device state from GPS.
Tested: targeted 17 tests; full app 573 tests; lint; production build; typecheck; public URL guard
Not-tested: authenticated browser visual smoke and deployment
Constraint: Shopify publishes no fixed webhook body maximum, so the 5 MiB default is a configurable application safety budget.
Rejected: Adopt the RED fixture's 2 MiB value or call request.text() before validation | Neither is an official platform limit and request.text() is unbounded.
Confidence: high
Scope-risk: narrow
Directive: Keep the byte limit ahead of SDK HMAC validation and Delivery forwarding; preserve streaming UTF-8 decoding and never log payload bytes.
Tested: targeted 17 tests; full app 579 tests; lint; production build; typecheck; public URL guard; main/dev/kfood compose config
Not-tested: production deployment and a live Shopify oversized delivery
Consolidate identical token failure state shaping and replace nested health classification while preserving fail-closed webhook, unknown-health, and legacy optional-field behavior.

Constraint: Preserve the verified Shopify remediation behavior exactly

Rejected: Redesign admission, receipt, token, or Pill contracts | Those boundaries are grounded and regression-covered

Confidence: high

Scope-risk: narrow

Directive: Keep unknown evidence explicit and webhook admission fail-closed

Tested: 579 tests; build; typecheck; lint; public URL guard; main and K-food compose config

Not-tested: Production runtime behavior is verified by the deployment story
Constraint: Settings and health endpoints may resolve only the authenticated session shop.
Rejected: Global or query-selected health state | it leaks failures across shops.
Confidence: high
Scope-risk: narrow
Directive: Keep token health reads keyed by trusted app and session identity.
Tested: Shopify app 582 tests; targeted token sync tests; lint; build; typecheck; public URL guard; compose config.
Not-tested: Production deploy, excluded by task.
Constraint: Preserve useful correlation and tenant observability without emitting raw errors, stacks, shop domains, or customer/order data.
Rejected: Sanitize arbitrary error strings | Allowlisting stable fields avoids future redaction bypasses.
Confidence: high
Scope-risk: narrow
Directive: Route external operational logs through the safe allowlist and hash shop identities before logging.
Tested: 4 hostile log tests; 164 targeted tests; 586 full tests; build; typecheck; lint; public URL guard.
Not-tested: Live production log ingestion.
Constraint: Preserve user-visible error behavior while removing raw external values from server and browser logs.
Rejected: Redact arbitrary messages in place | allowlisted stable fields avoid bypasses.
Confidence: high
Scope-risk: moderate
Directive: Keep new runtime logs behind allowlisted telemetry; hash authenticated shops.
Tested: 10 structural/hostile log tests; 210 targeted tests; 592 full tests; build; typecheck; lint; public URL guard.
Not-tested: Live production external log ingestion.
Constraint: Authenticated app loaders must not wait indefinitely on a half-open Delivery API.
Rejected: AbortSignal alone | injected fetch implementations may ignore abort and keep the shared in-flight promise pending.
Confidence: high
Scope-risk: narrow
Directive: Keep token exchange deadlines bounded and timeout health free of raw request or shop data.
Tested: 21 targeted token/log tests; 594 full tests; build; typecheck; lint; public URL guard.
Not-tested: Live production Delivery API half-open connection.
Constraint: Compliance HMAC authentication must receive exact bytes without buffering unbounded unauthenticated payloads.
Rejected: Clone then read the request | it duplicates the body and bypasses the shared streaming cap.
Confidence: high
Scope-risk: moderate
Directive: Keep order and compliance admission on the shared 5 MiB default and 10 MiB maximum.
Tested: 43 focused webhook/log tests; 597 full tests; build; typecheck; lint; public URL guard.
Not-tested: Live Shopify compliance delivery.
Constraint: Server IGNORED receipts are terminal only when explicitly suppressed and duplicate.
Rejected: Treat every unknown 200 receipt as durable | arbitrary statuses must remain retryable failures.
Confidence: high
Scope-risk: narrow
Directive: Keep Shopify durable receipt statuses synchronized with the Server terminal contract.
Tested: 32 focused webhook/log tests; 599 full tests; build; typecheck; lint; public URL guard.
Not-tested: Live redacted-shop webhook delivery.
Keep each target on an immutable commit image and restore verified SQLite state whenever migration, restart, or smoke validation fails.

Constraint: Manual EC2 workflow must preserve runtime env files and allow independent target deployments

Rejected: Shared-root rsync with a mutable local image | it cannot identify or restore the exact prior release

Confidence: high

Scope-risk: moderate

Directive: Keep current/previous pointer changes after candidate smoke and retain target-scoped locks

Tested: 607 Shopify tests; build; typecheck; lint; public URL guard; actionlint; shellcheck; YAML parse; K-food compose override config

Not-tested: Live EC2 rollback injection and production/K-food workflow dispatch are deferred to the authorized deployment stage
Constraint: Mandatory Shopify compliance deliveries must be HMAC-verified from the exact bounded raw body without session storage availability.
Rejected: authenticate.webhook admission | It couples compliance receipt to offline Admin session refresh and database health.
Confidence: high
Scope-risk: narrow
Directive: Keep compliance webhook admission session-free and acknowledge only durable Delivery receipts.
Tested: 601 node tests; focused compliance/store tests; lint; typecheck; build; Shopify SDK source pin; public URL guard
Not-tested: Live Shopify compliance delivery in production
Constraint: Deploy retries must remain recoverable across same-SHA builds, partial stops, signals, and legacy first transitions.\nRejected: Mutable rollback tags derived after build | same-SHA rebuilds can replace the only recoverable image.\nConfidence: high\nScope-risk: moderate\nDirective: Keep path validation, rollback snapshot proof, and recovery arming ahead of every remote mutation.\nTested: npm test (616/616); npm run build; npm run typecheck; npm run lint; npm run check:public-urls; actionlint; shellcheck; YAML parse; git diff --check\nNot-tested: Live EC2 deployment and production rollback
Constraint: The deployment hardening PR must include the verified G008 compliance head without rewriting either history.\nRejected: Rebase or cherry-pick | both would obscure the reviewed branch boundary or duplicate the compliance decision.\nConfidence: high\nScope-risk: moderate\nDirective: Preserve fbe1de0 as an ancestor of the deploy candidate.\nTested: Merge conflict check only; full Shopify verification follows on the combined head\nNot-tested: Live Shopify webhook delivery and EC2 deployment
Constraint: Device, server, sync, and alert evidence must remain independently visible without inferred green states.
Rejected: Clamp negative progress gaps to zero | It hides server-ahead mismatches as successful synchronization.
Confidence: high
Scope-risk: narrow
Directive: Preserve signed progress direction and require explicit empty alert evidence before rendering success.
Tested: 604 node tests; 48 focused operational tests; lint; typecheck; build; public URL guard
Not-tested: Live production route telemetry rendering
Constraint: Artifact preparation can fail after rollback pinning but before live runtime mutation.
Rejected: One recovery flag for both artifacts and runtime | it stops a healthy target during build-only failures.
Confidence: high
Scope-risk: moderate
Directive: Arm live recovery only immediately before stop and defer signals across the pointer commit.
Tested: deployment hardening/runtime tests 23/23; shellcheck; actionlint; git diff --check
Not-tested: Live EC2 deployment and production signal delivery
Constraint: The final Shopify candidate must include the updated G008 head without rewriting reviewed history.
Rejected: Cherry-pick | preserving branch ancestry keeps compliance and route-state review evidence intact.
Confidence: high
Scope-risk: moderate
Directive: Preserve 25e3bc3 and its fbe1de0 parent as ancestors of the deploy candidate.
Tested: Merge conflict check; full combined Shopify verification follows.
Not-tested: Live Shopify operations and EC2 deployment.
Constraint: Operators need the same no-op, artifact-cleanup, and pointer-signal guarantees enforced by the remote script.
Confidence: high
Scope-risk: narrow
Directive: Keep this runbook synchronized with deploy transaction and rollback tests.
Tested: git diff --check; combined Shopify tests 602/602 before documentation-only commit.
Not-tested: Live EC2 deployment.
Constraint: A healthy running image may outlive its missing exact-SHA tag, while previous points to an override that requires that tag.
Rejected: Retaining only rollback-<run-id> | successful cleanup deletes the sole image reference needed by previous.
Confidence: high
Scope-risk: moderate
Directive: Restore and verify the prior exact-SHA tag before committing new release pointers or deleting the temporary rollback pin.
Tested: focused deployment tests 24/24; full serial Shopify tests 603/603; compliance hang test isolated 1/1; build; typecheck; lint; public URL; actionlint; shellcheck; YAML; diff-check.
Not-tested: Live EC2 deployment and production rollback.
OziinG added 4 commits August 25, 2026 03:18
…cation

Constraint: GNU mv requires -T while BSD mv requires -h to atomically replace a destination symlink without dereferencing it.
Rejected: Global test serialization | CI failures were deterministic GNU/BSD option incompatibility, not shared test state.
Confidence: high
Scope-risk: narrow
Directive: Keep pointer replacement a same-filesystem atomic symlink rename on both GNU and BSD hosts.
Tested: default npm test twice (604/604 each); serial suite 604/604; focused deployment 25/25; GNU mv simulation 1/1; build; typecheck; lint; public URL; actionlint; shellcheck; YAML; diff-check.
Not-tested: Live EC2 deployment.
Constraint: A GNU-behavior harness must run identically on Linux and macOS without invoking either host-specific mv option internally.
Rejected: Removing the GNU regression | it is the direct guard for the CI failure.
Confidence: high
Scope-risk: narrow
Directive: Simulated GNU -T acceptance must perform a real atomic replacement without falling through to BSD -h.
Tested: GNU pointer regression 1/1; focused deployment tests 25/25; node syntax; diff-check.
Not-tested: Live EC2 deployment.
Constraint: A failed GNU rename must never be retried with BSD semantics against an unexpected directory path.
Rejected: Operational GNU-to-BSD fallback | it can convert a failed replacement into a successful move inside a directory.
Confidence: high
Scope-risk: moderate
Directive: Select one supported no-dereference rename mode before live mutation, reject non-symlink pointers, and verify readlink before publication.
Tested: focused deployment 27/27; default parallel full 606/606; target-directory and forced GNU failure 3/3; actionlint; shellcheck; YAML; node syntax; diff-check.
Not-tested: Live EC2 deployment.
Constraint: DB and runtime rollback must never proceed behind a pointer that may reference the candidate release.
Rejected: Exit immediately after a partial snapshot restore | that can leave current, previous, runtime, and DB describing different releases.
Confidence: high
Scope-risk: narrow
Directive: Restore previous before current; if snapshot restoration is not provable, republish and verify the complete candidate pointer set before fail-stop.
Tested: focused hostile pointer tests; node --test tests/*.test.mjs twice in parallel 609/609 each; serial 609/609; npm test 630/630; build; typecheck; lint; public URL guard; bash -n; shellcheck; actionlint; YAML parse; git diff --check
Not-tested: production deployment intentionally not run
@OziinG
OziinG merged commit b047c57 into main Aug 24, 2026
2 checks passed
@OziinG
OziinG deleted the codex/cc-265-shopify-deploy-hardening branch August 31, 2026 01:02
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