Skip to content

Finish BuilderSync publication and preview-safe authorization#2130

Open
3mdistal wants to merge 19 commits into
mainfrom
builder-sync-final-mile
Open

Finish BuilderSync publication and preview-safe authorization#2130
3mdistal wants to merge 19 commits into
mainfrom
builder-sync-final-mile

Conversation

@3mdistal

@3mdistal 3mdistal commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Summary

  • completes the guarded Content → Builder review and publication flow for the safe agent-native-blog-article-test model
  • adds read-only body-aware review previews, exact selected-row scoping, write reconciliation, execution timing, stable hydration, and media/table/quote fidelity fixes
  • adds a signed, one-shot two-hop Builder authorization relay so approved corporate callbacks can securely land credentials in the originating hosted Content database
  • documents the relay secret in every deployment locale and adds user-facing Content release notes

Local QA evidence

Published the rich QA article through the real Content UI to exactly one existing safe Builder entry (75972cb0094f4568a81bf80789505838). Final reconciliation proved:

  • published state: published
  • native images: 2
  • native video: 1
  • table: 1
  • list items: 7
  • blockquotes: 2
  • YouTube link: preserved
  • post-write selected review: no remaining diff

Server timings on the successful pass:

  • prepare review: 6.19s total
  • execute update: 4.08s total
  • Builder write dispatch: 0.41s

The production blog-article model was never used. Notion OAuth and Notion Sync are explicitly out of scope.

Verification

  • Content focused regression suite: 332 passed
  • Content database regression suite: 45 passed under repo-pinned Node 24.14.0
  • Core focused Builder/auth/relay suite: passed
  • cleanup regression suite: 125 passed
  • Content typecheck: passed
  • Core typecheck: passed
  • credential, query-scoping, route, and error-return guards: passed
  • formatting and diff checks: passed

Hosted rollout note

End-to-end hosted Builder authorization requires the same AGENT_NATIVE_BUILDER_RELAY_SECRET on the Content preview and the approved corporate callback deployment. The corporate workspace must consume the published core patch before its first-hop callback can relay.

The corporate callback now also requires AGENT_NATIVE_BUILDER_RELAY_TARGET_ORIGINS, a comma-separated exact-origin allowlist for trusted preview receivers. Wildcards are rejected, and the shared relay secret is enforced at 32 or more characters.

For Netlify, callback trust is additionally restricted to the immutable deploy-specific permalink (https://<24-hex-deploy-id>--<site>.netlify.app); mutable deploy-preview-* aliases are rejected even if configured.

The final hosted-preview check also found and fixed an independent connection gate: Builder account authorization remains available when branch-creation capability is not configured.

Hosted QA evidence

  • same-repository Netlify Deploy Preview provisioned successfully
  • isolated demo account signup and Content workspace load succeeded on the immutable deploy origin
  • Connect Builder remained enabled without Builder branch-creation configuration
  • the connection popup reached the preview relay setup gate and stopped safely before Builder authorization because AGENT_NATIVE_BUILDER_RELAY_SECRET is not configured
  • no hosted Builder write occurred

Hosted timings on the final pass:

  • document/settings navigation load: 1.71s
  • Builder connection-status calls: 2.08–2.57s warm, up to 5.44s cold

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Visual recap — not generated

The recap was suppressed because the diff matched a secret/credential pattern. No plan was published.

Reason: high-confidence secret in diff.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

builder-io-integration[bot]

This comment was marked as outdated.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@builder-io-integration builder-io-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Builder reviewed your changes and found 3 potential issues 🔴

Review Details

Code Review Summary

PR #2130 substantially expands the Content → Builder workflow with body-aware review and reconciliation, rich-content fidelity, stable hydration/timing, Slack artifact continuity, preview database isolation, and a signed hosted authorization relay. The overall architecture is strong: Builder writes are scoped to selected rows, access checks and owner scoping are preserved, relay secrets are validated, and the test coverage is extensive. This is high risk because it includes credential authorization, external writes, and preview database provisioning.

Key Findings

  • 🔴 HIGH — Ambiguous Builder transport failures are marked retryable without verifying whether the remote write already succeeded, so a retry can duplicate an externally applied write.
  • 🟡 MEDIUM — The selected-row preview path does not perform the authoritative Builder target-row backfill used by prepare, so partial snapshots can show an existing update as create_draft.
  • 🟡 MEDIUM — Neon action outputs are not validated before empty/invalid database URLs are written to Netlify preview configuration.

A prior relay-replay concern was not resubmitted because its relevant callback lines are unchanged and are not commentable in this PR diff; the current review is limited to actionable positions introduced by the latest PR head.

🧪 Browser testing: Planned 17 grounded UI test cases, but execution was blocked because the browser-test executor had no browser-control tools; the dev server was healthy.

`Builder write request failed with HTTP ${writeResult.status}.`;
await deps.markExecutionFailed({
executionId: execution.id,
state: writeResult.ambiguity ? "reconciliation_required" : "failed",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Verify ambiguous Builder writes before allowing retries

Timeout/transport ambiguity only means the response was lost; the Builder write may already have been applied. Marking this execution retryable without reconciling the target can allow a subsequent retry to repeat an externally successful write and leave local/remote state inconsistent. Query or reconcile the target after ambiguous dispatch before permitting a retry.

Fix in Builder

@3mdistal 3mdistal Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in the current branch: ambiguous transport/write results now persist the reconciliation_required state and throw a conflict that explicitly prevents retry. The execution path performs read-only intent lookup and reconciliation before any later attempt can proceed, and only marks success after remote evidence is reconciled locally.

.slice(0, BUILDER_SOURCE_REVIEW_PREPARE_LIMIT);
const review =
changeSets.length > 0
? buildBuilderSourceReviewPayload({ source, changeSets })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Backfill authoritative Builder rows in selected previews

This preview path builds the review directly from the current source snapshot, unlike prepare, which first backfills authoritative Builder target rows. For a partial snapshot, an existing selected remote entry can therefore be shown as create_draft with no target ID, causing the approval UI to describe a different operation from the later prepare/execute path. Apply the same authoritative-row reconciliation before constructing the preview payload.

Fix in Builder

@3mdistal 3mdistal Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in fbf8b9e. Read-only previews now call the same withAuthoritativeBuilderTargetRows backfill used by prepare before building the review payload. Added a database regression test covering a selected preview whose snapshot window omits the linked Builder row.

-d '{"value":"'"$VAL"'","context":"deploy-preview"}' \
-o /dev/null -w '' \
|| true
set_branch_value "$KEY" "$VAL"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Validate Neon database URL outputs before configuring Netlify

The Netlify environment step consumes the Neon action outputs without checking that both pooled and unpooled URLs are non-empty. If branch creation returns empty outputs while the action still exits successfully, the preview can be configured with blank database URLs and fail later with little diagnostic signal; fail the workflow before writing invalid values.

Fix in Builder

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved by scope removal in c1156ea. The BuilderSync PR no longer changes the Neon preview-branch workflow or Netlify database provisioning; that infrastructure work is being kept separate from the production BuilderSync path.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

@netlify

This comment has been minimized.

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