Skip to content

Added check=true validation - #2043

Open
sougata-progress wants to merge 3 commits into
mainfrom
sougata/bulk_promote_check
Open

Added check=true validation#2043
sougata-progress wants to merge 3 commits into
mainfrom
sougata/bulk_promote_check

Conversation

@sougata-progress

@sougata-progress sougata-progress commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Signed-off-by: sougata-progress <sougatab@progress.com>
Copilot AI lite review requested due to automatic review settings September 10, 2026 22:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved atomicity, metric, error-handling, and test issues remain.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds check=true compatibility validation for channel-to-channel promotions, including conflict detection, locking, rollback handling, and integration tests.

Changes:

  • Validates package dependency closures and returns HTTP 409 conflicts.
  • Adds advisory locking and transactional promotion handling.
  • Expands conflict, snapshot, rollback, and concurrency tests.
File summaries
File Summary and final review comments
test/builder-api/src/channels.js Adds validation and concurrency tests. Critical (1 vote): Configure requests to accept both 200 and 409 responses.
components/builder-db/src/models/channel.rs Adds advisory locking for promotions.
components/builder-api/src/server/resources/channels.rs Implements validation and transactional promotion. Critical (3 votes): Ensure all promotion paths share atomic locking/transaction handling. Moderate (3 votes): Preserve the channel-to-channel request metric. Moderate (1 vote): Preserve non-NotFound lookup errors.
components/builder-api/src/server/helpers.rs Computes channel package dependency closures.
Review details

Suppressed comments (1)

components/builder-api/src/server/resources/channels.rs:354

  • Channel::get(...).ok() turns every lookup error into None, not only NotFound. A database/query failure is therefore treated as an empty source closure, so the compatibility check can be skipped instead of returning the underlying error; preserve non-NotFound errors here.
            let source_channel_id = Channel::get(&origin, &ch_source, conn).ok().map(|c| c.id);
  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread components/builder-api/src/server/resources/channels.rs Outdated
Comment thread test/builder-api/src/channels.js
Comment thread components/builder-api/src/server/resources/channels.rs
Signed-off-by: sougata-progress <sougatab@progress.com>
Copilot AI review requested due to automatic review settings September 11, 2026 13:45
Copilot stopped reviewing on behalf of sougata-progress due to an error September 11, 2026 14:05
@sougata-progress
sougata-progress marked this pull request as ready for review September 11, 2026 14:07
@sougata-progress
sougata-progress requested a review from a team as a code owner September 11, 2026 14:07

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Note

Copilot was unable to run its full agentic suite in this review.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 6 comments.

Comment thread components/builder-api/src/server/resources/channels.rs Outdated
Comment thread components/builder-api/src/server/resources/channels.rs Outdated
Comment thread components/builder-db/src/models/channel.rs Outdated
Comment thread components/builder-api/src/server/resources/channels.rs Outdated
Comment thread components/builder-api/src/server/resources/channels.rs Outdated
Comment thread components/builder-api/src/server/resources/channels.rs Outdated
Signed-off-by: sougata-progress <sougatab@progress.com>
Copilot AI review requested due to automatic review settings September 11, 2026 20:40

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Three critical concurrency and error-handling issues remain unresolved.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 4/4 changed files
  • Comments generated: 3
  • Review effort level: Lite

Comment thread components/builder-api/src/server/resources/channels.rs
Comment thread components/builder-api/src/server/resources/channels.rs
Comment thread components/builder-api/src/server/resources/channels.rs
Copilot AI review requested due to automatic review settings September 11, 2026 21:29

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changes recommended

Unresolved transaction error-handling and advisory-lock ordering issues could cause incorrect results or deadlocks.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

components/builder-api/src/server/helpers.rs:294

  • The new compatibility closure depends on tdeps, but the added API tests only exercise a direct neurosis/testapp version conflict and a clean closure; none verifies that two otherwise-compatible heads are rejected when they bring different transitive dependency idents. A regression in this loop could therefore make check=true miss dependency conflicts. Add an integration case using a package with a dependency (for example the existing testapp3 fixture) and assert the dependency-only conflict returns 409.
    for pkg in &head_packages {
        idents.push(pkg.ident.clone());
        idents.extend(pkg.tdeps.iter().cloned());
    }

components/builder-api/src/server/resources/channels.rs:371

  • This lock set does not cover package deletion: resources/pkgs.rs removes all origin_channel_packages rows for a package without acquiring the same advisory lock. A deletion can commit between the closure read and the later package-id read/write here, so check=true may validate a different membership set (or race the association insert) and return a false conflict or a non-atomic result. Coordinate package deletion with the same channel/package lock before relying on this transaction for check/write atomicity.
        // Serialize this whole read-then-write sequence (check and promote)
        // against every other path that can mutate either channel's package
        // membership -- bulk or single-package promote/demote -- so a
        // concurrent write can't land between this request's check and its
        // own write, on either the source or the target side. Held for the
        // duration of the transaction.
        lock_channels(&origin, ch_source.as_str(), ch_target.as_str(), conn)?;
  • Files reviewed: 5/5 changed files
  • Comments generated: 2
  • Review effort level: Lite

Comment thread components/builder-db/src/models/package.rs Outdated
Comment thread components/builder-db/src/models/package.rs Outdated
Copilot AI review requested due to automatic review settings September 11, 2026 21:46
@sougata-progress
sougata-progress force-pushed the sougata/bulk_promote_check branch from 50f3859 to 34e4d50 Compare September 11, 2026 21:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Unresolved issues remain around error propagation and incomplete locking coverage for concurrent deletions and package uploads.

Review details

Suppressed comments (3)

components/builder-api/src/server/resources/channels.rs:388

  • ok() discards every Channel::get error, not just NotFound. A database/transaction error is therefore treated as an absent source and the code continues into the package lookup/write path, masking the original failure as a later generic error (and potentially changing the returned status). Match NotFound explicitly if an absent source is meant to remain an empty source, and propagate all other errors.
        let source_channel_id = Channel::get(&origin, &ch_source, conn).ok().map(|c| c.id);

components/builder-api/src/server/resources/channels.rs:359

  • These advisory locks only coordinate callers that take the new lock; delete_channel and package deletion still remove channel memberships without it. A concurrent delete can remove the target after the compatibility check or before promote_packages, causing a rollback/error or a successful response whose result is immediately deleted, so the read/check/write atomicity claimed here is incomplete. Make membership/channel deletion take the same per-channel lock before relying on this concurrency guarantee.
        lock_channels(&origin, ch_source.as_str(), ch_target.as_str(), conn)?;

components/builder-api/src/server/resources/channels.rs:359

  • These advisory locks do not cover the package-upload path: Package::create inserts/updates a package and then calls OriginChannelPackage::promote for unstable without acquiring lock_channel (builder-db/src/models/package.rs:558-588). An upload can add a source package after channel_package_closure runs but before the package list is read, so it can be promoted without compatibility validation. Acquire the same lock around that mutation (and cover other channel-membership deletion paths) before relying on this transaction for atomic validation.
        lock_channels(&origin, ch_source.as_str(), ch_target.as_str(), conn)?;
  • Files reviewed: 4/4 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

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.

2 participants