Skip to content

Hardening checks for applicable embargoes#44

Closed
bibliophileaxe wants to merge 1 commit intomainfrom
bugfix
Closed

Hardening checks for applicable embargoes#44
bibliophileaxe wants to merge 1 commit intomainfrom
bugfix

Conversation

@bibliophileaxe
Copy link
Contributor

@bibliophileaxe bibliophileaxe commented Aug 19, 2025

Bug

On enabling https://www.drupal.org/project/mercury_editor the node/add page whitescreens.

Stacktrace:
The website encountered an unexpected error. Try again later. Drupal\Core\Database\InvalidQueryException: Query condition 'embargo.embargoed_node IN ()' cannot be empty. in Drupal\Core\Database\Query\Condition->condition() (line 108 of core/lib/Drupal/Core/Database/Query/Condition.php).

Do not check for applicable embargoes if a new object is being added.

Summary by CodeRabbit

  • Bug Fixes
    • Embargo evaluation now ignores newly created (unsaved) content, preventing premature embargo lookups on drafts. Embargo rules continue to apply once content is saved.
    • No changes to embargo handling for media and files; their behavior remains consistent.

@bibliophileaxe bibliophileaxe added the patch Backwards compatible bug fixes. label Aug 19, 2025
@coderabbitai
Copy link

coderabbitai bot commented Aug 19, 2025

Walkthrough

A conditional was added to the NodeInterface branch of getApplicableEmbargoes in src/EmbargoStorageTrait.php to only process non-new nodes (isNew() === FALSE). Embargo resolution for MediaInterface/FileInterface remains unchanged. No public signatures were modified.

Changes

Cohort / File(s) Summary
Embargo resolution logic
src/EmbargoStorageTrait.php
Gate NodeInterface embargo lookup behind isNew() === FALSE; newly created nodes no longer queried via embargoed_node. Media/File lookup paths unchanged. No public API signature changes.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant EmbargoStorageTrait
  participant Storage as EntityStorage
  participant LUT as Lookup/Join

  Caller->>EmbargoStorageTrait: getApplicableEmbargoes(entity)
  alt entity is NodeInterface
    alt entity.isNew() === FALSE
      EmbargoStorageTrait->>Storage: load by embargoed_node (node id)
      Storage-->>EmbargoStorageTrait: embargo list (possibly empty)
    else entity.isNew() === TRUE
      note over EmbargoStorageTrait: Skip node embargo lookup
    end
  else entity is MediaInterface/FileInterface
    EmbargoStorageTrait->>LUT: map to embargoed_node via LUT join
    LUT-->>EmbargoStorageTrait: related IDs (possibly none)
    EmbargoStorageTrait->>Storage: loadMultiple(IDs)
    Storage-->>EmbargoStorageTrait: embargo list (possibly empty)
  end
  EmbargoStorageTrait-->>Caller: applicable embargoes (array)
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

I thump my paw: “Save first, then see!”
New nodes hop past the embargo tree.
Media and files still take their turn,
Through lookup lanes where mappings churn.
A careful nibble, a tidy flow—
Carrots cached, and on we go. 🥕🐇

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

Warning

Review ran into problems

🔥 Problems

Errors were encountered while retrieving linked issues.

Errors (1)
  • JIRA integration encountered authorization issues. Please disconnect and reconnect the integration in the CodeRabbit UI.
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch bugfix

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
src/EmbargoStorageTrait.php (1)

52-61: Extend the “new entity” skip to Media/File for consistency with PR intent

The PR states “Do not check for applicable embargoes if a new object is being added.” Currently, Media/File embargo lookups will still run for unsaved entities (with a NULL id). While it likely returns an empty result set, it still performs an unnecessary join and query and diverges from the stated objective.

Recommend guarding Media/File with the same isNew() check:

-    elseif ($entity instanceof MediaInterface || $entity instanceof FileInterface) {
+    elseif (($entity instanceof MediaInterface || $entity instanceof FileInterface) && $entity->isNew() === FALSE) {
       $query = $this->database->select('embargo', 'e')
         ->fields('e', ['id'])
         ->distinct();
       $lut_alias = $query->join(LUTGeneratorInterface::TABLE_NAME, 'lut', '%alias.nid = e.embargoed_node');
       $key = $entity instanceof MediaInterface ? 'mid' : 'fid';
       $query->condition("{$lut_alias}.{$key}", $entity->id());
       $ids = $query->execute()->fetchCol();
       return $this->loadMultiple($ids);
     }
  • Keeps behavior consistent across entity types.
  • Avoids a LUT join with a NULL id on create flows.

Can you confirm whether the PR intent is to skip embargo checks for all new entities (Node/Media/File), not just Nodes?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between a481d32 and 7e801ed.

📒 Files selected for processing (1)
  • src/EmbargoStorageTrait.php (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: PHPUnit / Drupal 10.2 | PHP 8.2
  • GitHub Check: PHPUnit / Drupal 10.3 | PHP 8.3
  • GitHub Check: PHPUnit / Drupal 10.3 | PHP 8.2
  • GitHub Check: PHPUnit / Drupal 10.2 | PHP 8.3
🔇 Additional comments (1)
src/EmbargoStorageTrait.php (1)

48-51: Good guard: skip embargo lookup for unsaved nodes

Adding && $entity->isNew() === FALSE prevents lookups with a NULL nid and avoids unnecessary DB work. This aligns with the PR objective.

@bibliophileaxe
Copy link
Contributor Author

bibliophileaxe commented Aug 19, 2025

Closing this PR, will raise a ticket to fix this.

More context:

The error is triggered from:

foreach ($request->attributes->all() as $attribute) {

where it's going over all request attributes and is not just constrained to objects that should be checked.

Probably needs to be fixed here:

/**
* {@inheritdoc}
*/
public function access(EntityInterface $entity, AccountInterface $user) {
$type = $this->entityTypeManager->getDefinition('embargo');
$state = AccessResult::neutral();
if ($user->hasPermission('bypass embargo access')) {
return $state->setReason('User has embargo bypass permission.')
->addCacheContexts(['user.permissions']);
}
/** @var \Drupal\embargo\EmbargoStorage $storage */
$storage = $this->entityTypeManager->getStorage('embargo');
$state->addCacheTags($type->getListCacheTags())
->addCacheContexts($type->getListCacheContexts());
$related_embargoes = $storage->getApplicableEmbargoes($entity);
if (empty($related_embargoes)) {
return $state->setReason('No embargo statements for the given entity.');
}
array_map([$state, 'addCacheableDependency'], $related_embargoes);
$embargoes = $storage->getApplicableNonExemptNonExpiredEmbargoes(
$entity,
$this->request->server->get('REQUEST_TIME'),
$user,
$this->request->getClientIp()
);
return $state->andIf(AccessResult::forbiddenIf(
!empty($embargoes),
$this->formatPlural(
count($embargoes),
'1 embargo preventing access.',
'@count embargoes preventing access.'
)->render()
));
}

where we add embargo entities as parameters to routes and only check those.

Copy link
Contributor

@adam-vessey adam-vessey left a comment

Choose a reason for hiding this comment

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

Could still explode if we were hitting on a new media or file.

That said something being allowed/trying to perform an access check on something that has not yet been ingested feels like something else going wrong elsewhere. Bit of discussion, seems to be something off in IpRangeRedirect being insufficiently specific... should possibly make things more specific, constrain what we consider based on the _access_result attribute from the request, when/if present?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patch Backwards compatible bug fixes.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants