Skip to content

Finish BuilderSync publication and preview-safe authorization#2130

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

Finish BuilderSync publication and preview-safe authorization#2130
3mdistal wants to merge 13 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 an isolated hosted preview database
  • isolates Netlify preview database values by same-repository PR branch and makes provisioning failures loud
  • preserves participant-visible Slack replies, provider delivery references, and verified Content artifact IDs so thread corrections can update a renamed Design Ask instead of creating a duplicate
  • teaches Content to distinguish update/add/supersede/create intent and to keep verified Requester identity separate from a named Assignee
  • 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.

The Slack correction flow has a frozen post-deploy test in private #test-content-app: create one disposable Design Ask, rename it in Content, correct it in the same Slack thread, and verify the original Content ID is updated with Requester preserved and Assignee resolved. This cannot run against the PR before merge because the workspace has no preview Slack bot or webhook environment; it remains an explicit post-deploy gate.

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/Slack suite: 378 passed
  • Content typecheck: passed
  • Core typecheck: passed
  • credential, query-scoping, route, and error-return guards: passed
  • formatting and diff checks: passed

Hosted rollout note

The same-repository PR should provision the Content Netlify Deploy Preview and its Neon branch. End-to-end hosted Builder authorization additionally 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 and isolated Neon branch 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

.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

-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

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