Skip to content

Conversation

@withinboredom
Copy link
Member

@withinboredom withinboredom commented Aug 2, 2025

Summary by CodeRabbit

  • New Features

    • Added a new event wrapper to track the source of each event for improved traceability.
    • Introduced an attribute to specify allowed creation sources for entities.
    • Enhanced permission system with origin-based filtering for resource creation.
  • Improvements

    • Enhanced event metadata to consistently include origin information across various actions.
    • Improved type safety and clarity in event representations and string outputs.
    • Updated event property accessibility for better integration and flexibility.
    • Extended resource discovery and authorization to consider source identifiers.
    • Added explicit permission checks for share-related events to enforce access control.
    • Implemented attribute-based access control checks on entity and activity operations, enforcing security restrictions.
    • Enriched event dispatching and orchestration with source context for better provenance tracking.
    • Refined resource permission logic to include origin-based validation.
    • Added new global constants representing API and system sources for authorization context.
    • Included source context in HTTP API requests and authorization headers.
  • Bug Fixes

    • Minor corrections to type declarations in event methods for stricter typing compliance.

Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
@coderabbitai
Copy link

coderabbitai bot commented Aug 2, 2025

Walkthrough

This update introduces a new WithFrom event wrapper class and systematically applies it to all event dispatches within both EntityContext and OrchestrationContext, enriching events with their source context. Several event wrapper classes are refactored for property visibility and immutability. Method signatures are updated for stricter typing, and interface/property contracts are clarified.

Changes

Cohort / File(s) Change Summary
Event Source Wrapping in Contexts
src/EntityContext.php, src/OrchestrationContext.php
Added private addFrom() method to wrap all dispatched events with WithFrom, embedding source context (entity/orchestration ID). All event dispatches now use this wrapper.
New Event Wrapper
src/Events/WithFrom.php
Introduced WithFrom class to encapsulate an event and its source (StateId). Includes constructor, static factory, string representation, and getter.
Event Class Refactor
src/Events/Event.php
Implements Stringable (imported), updates $timestamp type, and changes $eventId to have custom getter/setter logic that cascades to inner events if present.
Inner Event Interface/Property Contract
src/Events/HasInnerEventInterface.php
Adds public read-only property innerEvent to interface, requiring implementing classes to expose it.
Event Wrapper Property Visibility
src/Events/WithEntity.php, src/Events/WithActivity.php, src/Events/WithOrchestration.php, src/Events/WithPriority.php
Changes innerEvent property to be public (and/or public readonly) for easier access and mutation. Minor reformatting of method attributes.
Delay Event Typing
src/Events/WithDelay.php
Switches from fully qualified \DateTimeImmutable to imported type, updates method signatures, and removes redundant event ID assignment.
Event Class String Typing
src/Events/RevokeUser.php, src/Events/ShareWithRole.php, src/Events/ShareWithUser.php
Adds explicit : string return type to __toString() methods.
ShareOwnership Metadata
src/Events/ShareOwnership.php
Adds #[NeedsSource(Operation::Owner)] attribute and explicit string return type to __toString(). Imports relevant classes.
Test Wrapper Update
tests/Unit/EventDescriptionTest.php
Changes mock event wrapper to use a public innerEvent property for consistency with production code.
Authorization Enhancements and Resource Filtering
cli/auth/createPermissions.go, cli/auth/resource.go, cli/auth/resourceManager.go, cli/lib/consumer.go, cli/lib/api.go
Added FromId and FromType fields to permissions and resource structs. Modified resource creation and discovery methods to include from context for permission filtering. Updated authorization checks in consumer to enforce share-related permissions and pass sourceId in resource discovery calls.
ID and StateId Enhancements
cli/ids/id.go
Added global ApiSource and SystemSource variables. Modified StateId.Name() to return IdKind type and added JSON struct tags. Removed __invoke method from StateId.
Permission Metadata Extension
src/Glue/glue.php, src/State/Attributes/AllowCreateFrom.php
Added support for new AllowCreateFrom attribute in permission extraction logic. Introduced AllowCreateFrom attribute class to annotate allowed creation sources with validation.
Event Description Update
src/Events/EventDescription.php
Added nullable from property. Updated event description logic to extract from from WithFrom events.
Auth Context Enhancements
src/Contexts/AuthContext.php, src/Contexts/AuthContext/functions.php, src/Contexts/AuthContext/SecurityException.php
Added fromTypes and fromIds properties to AuthContext. Defined global constants ApiSource and SystemSource. Added SecurityException class for auth errors.
Access Control Attributes and Enforcement
src/State/Attributes/*.php, src/State/AbstractHistory.php, src/State/ActivityHistory.php, src/State/EntityHistory.php
Introduced AccessControl interface and multiple attribute classes (AllowCreateFrom, AllowAnyOperation, DenyAnyOperation, and updates to existing allow attributes). Added checkAccessControl method to AbstractHistory to evaluate access based on attributes and provenance. Enforced access control in ActivityHistory and EntityHistory during task execution and operation invocation, throwing SecurityException on denial.
Task State Update
src/Task.php
Sets the from property on the state object during task run to the current glue source.
Test Adjustments for from Property
tests/Unit/ActivityHistoryTest.php, tests/Unit/EntityHistoryTest.php, tests/Unit/LockIntegrationTest.php
Added assignments of from property with appropriate StateId instances in test setups for consistency with new access control and provenance handling.

Sequence Diagram(s)

sequenceDiagram
    participant Context as EntityContext/OrchestrationContext
    participant Event as Event
    participant WithFrom as WithFrom
    participant Dispatcher as EventDispatcher/TaskController

    Context->>Event: Create event (e.g., Signal, Delay, Orchestration)
    Context->>WithFrom: addFrom(event)
    WithFrom-->>Context: Event wrapped with source StateId
    Context->>Dispatcher: fire(wrapped event)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~35 minutes

Poem

🐇✨
In fields of code where events now roam,
Each carries its source, a provenance home.
Wrappers abound, with properties clear,
Refactored for access, intent sincere.
Typings are strict, interfaces neat—
This bunny hops on, with changes complete!

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add/from

🪧 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.
    • Explain this complex logic.
    • 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. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • 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 src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

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

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

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

Documentation and Community

  • 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.

@codecov
Copy link

codecov bot commented Aug 2, 2025

Codecov Report

❌ Patch coverage is 46.76617% with 107 lines in your changes missing coverage. Please review.
✅ Project coverage is 46.85%. Comparing base (e49d080) to head (90d1d93).
⚠️ Report is 1 commits behind head on v2.

Files with missing lines Patch % Lines
src/EntityContext.php 2.08% 47 Missing ⚠️
src/OrchestrationContext.php 50.00% 20 Missing ⚠️
src/Glue/glue.php 0.00% 9 Missing ⚠️
src/State/EntityHistory.php 25.00% 9 Missing ⚠️
src/State/AbstractHistory.php 84.90% 8 Missing ⚠️
src/State/ActivityHistory.php 42.85% 4 Missing ⚠️
src/Events/WithFrom.php 75.00% 2 Missing ⚠️
src/State/Attributes/AllowCreateFrom.php 60.00% 2 Missing ⚠️
src/Events/EventDescription.php 50.00% 1 Missing ⚠️
src/Events/RevokeUser.php 0.00% 1 Missing ⚠️
... and 4 more
Additional details and impacted files
@@             Coverage Diff              @@
##                 v2     #154      +/-   ##
============================================
+ Coverage     46.31%   46.85%   +0.54%     
- Complexity     1250     1313      +63     
============================================
  Files            99      103       +4     
  Lines          3565     3677     +112     
============================================
+ Hits           1651     1723      +72     
- Misses         1914     1954      +40     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions
Copy link

github-actions bot commented Aug 2, 2025

Performance Metrics

test time (s) memory usage
perf 45.82 102
Fan out/in 60.06 8

Performance Metrics

test time (s) memory usage
perf 15.85 170
Fan out/in 60.05 8

Performance Metrics

test time (s) memory usage
perf 44.95 102
Fan out/in 60.06 8

Performance Metrics

test time (s) memory usage
perf 78.85 102
Fan out/in 60.06 8

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: 5

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e49d080 and a68af98.

📒 Files selected for processing (15)
  • src/EntityContext.php (8 hunks)
  • src/Events/Event.php (1 hunks)
  • src/Events/HasInnerEventInterface.php (1 hunks)
  • src/Events/RevokeUser.php (1 hunks)
  • src/Events/ShareOwnership.php (2 hunks)
  • src/Events/ShareWithRole.php (1 hunks)
  • src/Events/ShareWithUser.php (1 hunks)
  • src/Events/WithActivity.php (1 hunks)
  • src/Events/WithDelay.php (1 hunks)
  • src/Events/WithEntity.php (1 hunks)
  • src/Events/WithFrom.php (1 hunks)
  • src/Events/WithOrchestration.php (1 hunks)
  • src/Events/WithPriority.php (2 hunks)
  • src/OrchestrationContext.php (10 hunks)
  • tests/Unit/EventDescriptionTest.php (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (8)
src/Events/ShareWithRole.php (5)
src/Events/RevokeUser.php (1)
  • __toString (44-47)
src/Events/ShareOwnership.php (1)
  • __toString (44-47)
src/Events/ShareWithUser.php (1)
  • __toString (45-48)
src/Events/GiveOwnership.php (1)
  • __toString (41-44)
src/Events/RevokeRole.php (1)
  • __toString (44-47)
src/Events/RevokeUser.php (11)
src/Events/WithActivity.php (1)
  • __toString (53-56)
src/Events/WithFrom.php (1)
  • __toString (19-22)
src/Events/WithOrchestration.php (1)
  • __toString (55-58)
src/Events/WithPriority.php (1)
  • __toString (56-59)
tests/Unit/EventDescriptionTest.php (6)
  • __toString (55-58)
  • __toString (69-72)
  • __toString (83-86)
  • __toString (103-106)
  • __toString (125-128)
  • __toString (140-143)
src/Events/ShareOwnership.php (1)
  • __toString (44-47)
src/Events/ShareWithRole.php (1)
  • __toString (45-48)
src/Events/ShareWithUser.php (1)
  • __toString (45-48)
src/State/Ids/StateId.php (1)
  • __toString (178-181)
src/Events/RevokeRole.php (1)
  • __toString (44-47)
src/State/OrchestrationInstance.php (1)
  • __toString (41-44)
src/Events/ShareWithUser.php (5)
src/Events/RevokeUser.php (1)
  • __toString (44-47)
src/Events/ShareOwnership.php (1)
  • __toString (44-47)
src/Events/ShareWithRole.php (1)
  • __toString (45-48)
src/Events/GiveOwnership.php (1)
  • __toString (41-44)
src/Events/RevokeRole.php (1)
  • __toString (44-47)
src/Events/WithEntity.php (3)
src/Events/WithActivity.php (1)
  • __construct (33-36)
src/Events/Event.php (1)
  • __construct (41-53)
src/Events/WithFrom.php (1)
  • __construct (9-12)
tests/Unit/EventDescriptionTest.php (8)
src/Events/WithActivity.php (2)
  • getInnerEvent (43-46)
  • __toString (53-56)
src/Events/WithEntity.php (2)
  • getInnerEvent (45-48)
  • __toString (55-58)
src/Events/WithFrom.php (2)
  • getInnerEvent (24-27)
  • __toString (19-22)
src/Events/WithOrchestration.php (2)
  • getInnerEvent (45-48)
  • __toString (55-58)
src/Events/WithPriority.php (1)
  • __toString (56-59)
src/Events/WithDelay.php (2)
  • getInnerEvent (46-49)
  • __toString (51-54)
src/Events/HasInnerEventInterface.php (1)
  • getInnerEvent (31-31)
src/Events/WithLock.php (2)
  • getInnerEvent (59-62)
  • __toString (54-57)
src/Events/WithActivity.php (5)
src/Events/Event.php (1)
  • __construct (41-53)
src/Events/WithEntity.php (1)
  • __construct (31-34)
src/Events/WithOrchestration.php (1)
  • __construct (32-38)
src/Events/AwaitResult.php (1)
  • __construct (35-38)
cli/ids/id.go (1)
  • StateId (176-179)
src/Events/WithDelay.php (6)
src/Events/WithActivity.php (2)
  • __construct (33-36)
  • forEvent (38-41)
src/Events/Event.php (1)
  • __construct (41-53)
src/Events/WithFrom.php (2)
  • __construct (9-12)
  • forEvent (14-17)
src/Events/WithOrchestration.php (1)
  • __construct (32-38)
src/Events/WithPriority.php (1)
  • __construct (31-34)
tests/Unit/EventDescriptionTest.php (1)
  • __construct (50-53)
src/Events/WithFrom.php (6)
src/Events/WithActivity.php (4)
  • __construct (33-36)
  • forEvent (38-41)
  • __toString (53-56)
  • getInnerEvent (43-46)
src/Events/Event.php (1)
  • __construct (41-53)
src/Events/WithEntity.php (3)
  • __construct (31-34)
  • __toString (55-58)
  • getInnerEvent (45-48)
src/Events/WithOrchestration.php (3)
  • __construct (32-38)
  • __toString (55-58)
  • getInnerEvent (45-48)
src/EntityContext.php (1)
  • __construct (66-80)
src/Events/HasInnerEventInterface.php (1)
  • getInnerEvent (31-31)
🪛 PHPMD (2.15.0)
src/Events/WithDelay.php

32-32: Avoid unused parameters such as '$eventId'. (Unused Code Rules)

(UnusedFormalParameter)

🔇 Additional comments (22)
src/Events/ShareWithRole.php (1)

45-45: LGTM: Explicit return type improves type safety.

Adding the explicit : string return type declaration enhances type safety and IDE support while maintaining backward compatibility. This change aligns with similar updates across other event classes in the codebase.

src/Events/ShareWithUser.php (1)

45-45: LGTM: Consistent type safety improvement.

Adding the explicit : string return type declaration maintains consistency with other event classes and improves type safety. The implementation remains functionally identical.

src/Events/WithOrchestration.php (1)

35-35: LGTM: Property visibility change aligns with interface requirements.

Changing the innerEvent property from private readonly to public readonly provides direct access to the inner event while maintaining immutability. This change aligns with the updated HasInnerEventInterface requirements and supports the event wrapping pattern without compromising encapsulation.

src/Events/RevokeUser.php (1)

44-44: LGTM: Consistent return type declaration.

Adding the explicit : string return type follows the established pattern across event classes and improves type safety without any functional changes.

src/Events/HasInnerEventInterface.php (1)

29-30: No action needed: PHP ≥8.4 is already enforced and all event types expose innerEvent.

– composer.json requires "php": ">=8.4"
– All classes carrying an innerEvent (e.g. in src/Events/*) already declare it as a public property
– No additional implementers of HasInnerEventInterface need updating

tests/Unit/EventDescriptionTest.php (1)

148-161: LGTM! Test mock properly aligned with interface changes.

The MockWrapperEvent class correctly implements the updated HasInnerEventInterface pattern by:

  • Standardizing property name from $inner to $innerEvent
  • Making the property public for consistency with other wrapper classes
  • Updating all references accordingly

This ensures test coverage remains accurate for the new event wrapper architecture.

src/Events/WithPriority.php (1)

61-62: LGTM! Improved attribute formatting.

Moving the #[\Override] attribute to its own line improves readability and follows PHP coding standards.

src/Events/ShareOwnership.php (3)

27-28: LGTM! Proper imports for event sourcing attributes.

The imports correctly bring in the NeedsSource attribute and Operation enum to support the event provenance system.


31-31: LGTM! Event properly annotated for ownership operations.

The #[NeedsSource(Operation::Owner)] attribute correctly indicates this event requires source context for ownership operations, supporting the WithFrom wrapping pattern.


44-44: LGTM! Explicit return type improves type safety.

Adding the explicit string return type to __toString() improves type safety and follows PHP best practices.

src/OrchestrationContext.php (3)

38-38: LGTM!

The import is correctly placed and follows the existing import organization pattern.


81-86: LGTM!

The event wrapping is correctly applied to add source context to the activity call.


158-164: Consistent application of source tracking

All event dispatches are properly wrapped with addFrom(), ensuring consistent source tracking throughout the orchestration context. The implementation correctly handles both synchronous and asynchronous event patterns.

Also applies to: 169-179, 215-221, 236-241, 407-407, 418-423, 648-648, 669-669

src/EntityContext.php (4)

64-64: Correct implementation of source tracking

The use of a private readonly property initialized in the constructor is the correct approach, avoiding the static variable issue found in OrchestrationContext.

Also applies to: 79-79


132-135: Clean and efficient wrapper method

The addFrom method is concise and correctly wraps events with the source context.


101-104: Verify: Events in return method are not wrapped with source context

The events dispatched in the return method are not wrapped with addFrom(), unlike all other event dispatches in this class. If this is intentional (e.g., because these events target orchestrations rather than entities), please add a comment explaining why source tracking is not needed here.


120-125: Consistent source tracking across all entity operations

All entity-related event dispatches are properly wrapped with addFrom(), ensuring traceability of event origins.

Also applies to: 155-160, 201-206, 218-223, 230-235, 242-247, 254-259, 266-271, 278-283

src/Events/WithFrom.php (1)

1-28: Well-designed event wrapper implementation

The WithFrom class follows the established pattern of other event wrappers and correctly implements source tracking functionality. The use of a static factory method and the readable __toString() implementation are good design choices.

src/Events/WithDelay.php (2)

27-27: Good refactoring to use imports

Using import statements instead of fully qualified class names improves readability.

Also applies to: 32-32, 37-37


46-49: Correct removal of eventId synchronization

The removal of the $this->innerEvent->eventId = $this->eventId; line is appropriate since the Event base class now handles eventId synchronization for inner events.

src/Events/Event.php (2)

30-30: Clean refactoring with proper imports

Good practice to use import statements and explicitly declare the Stringable interface implementation.

Also applies to: 32-32, 35-35, 39-39


41-49: Elegant eventId synchronization using property hooks

The property hook implementation ensures that eventId changes are automatically propagated to inner events, maintaining consistency across wrapped events. This is a clean solution to the synchronization problem.

Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
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: 6

🧹 Nitpick comments (2)
cli/auth/resourceManager.go (1)

48-50: Update function documentation to include the new from parameter.

The function comment for DiscoverResource should be updated to document the new from *ids.StateId parameter and its purpose.

 // DiscoverResource is a method of the ResourceManager struct that is responsible for discovering a resource based on
-// the provided context, state ID, logger, and preventCreation flag
+// the provided context, state ID, from state ID, logger, and preventCreation flag
 func (r *ResourceManager) DiscoverResource(ctx context.Context, id *ids.StateId, from *ids.StateId, logger *zap.Logger, preventCreation bool) (*Resource, error) {
cli/auth/resource.go (1)

55-56: Consider using a set structure for AllowedFromTypes

For consistency with the Owners field which uses map[UserId]struct{} as a set, consider using map[string]struct{} for AllowedFromTypes to avoid duplicates and improve lookup performance.

-	AllowedFromTypes []string       `json:"allowed_from_types"`
+	AllowedFromTypes map[string]struct{} `json:"allowed_from_types"`
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between a68af98 and a8379d7.

📒 Files selected for processing (9)
  • cli/auth/createPermissions.go (1 hunks)
  • cli/auth/resource.go (5 hunks)
  • cli/auth/resourceManager.go (2 hunks)
  • cli/ids/id.go (3 hunks)
  • cli/lib/api.go (11 hunks)
  • cli/lib/consumer.go (10 hunks)
  • src/Events/EventDescription.php (2 hunks)
  • src/Glue/glue.php (3 hunks)
  • src/State/Attributes/AllowCreateFrom.php (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • cli/auth/createPermissions.go
🧰 Additional context used
🧬 Code Graph Analysis (3)
cli/lib/api.go (1)
cli/ids/id.go (1)
  • ApiSource (17-20)
src/State/Attributes/AllowCreateFrom.php (1)
cli/ids/id.go (1)
  • EntityId (139-142)
cli/auth/resourceManager.go (2)
cli/ids/id.go (1)
  • StateId (181-184)
cli/auth/resource.go (1)
  • Resource (48-59)
⏰ 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). (2)
  • GitHub Check: build-docker
  • GitHub Check: Unit Tests - PHP
🔇 Additional comments (15)
cli/ids/id.go (2)

182-183: LGTM!

The JSON struct tags are properly formatted and follow Go conventions. The omitempty option is appropriate for these fields.


81-87: Breaking change impact verified – no updates needed

I searched the entire repo for calls to StateId.Name() and only found it used as a map key in cli/auth/resource.go (via cache.Store(id.Name(), …) / cache.Load(id.Name())). Since IdKind is an underlying string, using it as an interface{} key continues to work, and there are no other callers expecting a plain string return. No further changes are required here.

src/Events/EventDescription.php (2)

44-44: LGTM!

The new from property is properly typed as nullable StateId and follows the existing pattern of other optional properties in the class.


100-102: LGTM!

The WithFrom handling logic follows the same pattern as other event wrapper checks in the loop. The instanceof check and property assignment are correctly implemented.

cli/lib/api.go (1)

265-265: LGTM!

All DiscoverResource method calls are consistently updated with the new ids.ApiSource parameter in the correct position. The changes align with the method signature enhancement to support "from" context in resource discovery.

Also applies to: 315-315, 357-357, 433-433, 488-488, 574-574, 685-685, 761-761, 816-816, 881-881, 1035-1035

src/State/Attributes/AllowCreateFrom.php (3)

11-12: LGTM!

The attribute definition correctly targets classes and allows repetition, which is appropriate for specifying multiple allowed creation sources.


14-19: LGTM!

The type definitions are well-designed. The template annotation properly constrains the $type parameter to EntityState subclasses, and the union type for $id appropriately handles both entity and orchestration instances.


21-27: LGTM!

The constructor validation correctly enforces mutual exclusivity between $type and $id parameters. The logic is sound and the error messages are clear and helpful.

src/Glue/glue.php (2)

39-39: LGTM!

The import statement for AllowCreateFrom is correctly placed and follows the existing pattern of importing attribute classes.


262-263: LGTM!

The new array keys 'from' and 'from-type' are properly initialized following the existing pattern of other permission arrays.

cli/auth/resource.go (2)

106-107: Good simplification!

The removal of the redundant nil check is appropriate since currentUser is already validated at the beginning of the method.


128-135: Enhanced security with source-based authorization

The addition of the from parameter and the AllowedFrom check strengthens security by ensuring resources can only be created from authorized sources.

cli/lib/consumer.go (3)

156-167: Good naming improvement

The rename from shouldCreate to preventCreation makes the boolean's purpose clearer and the logic more intuitive.


268-303: Clarify the difference between ShareOwnership and GiveOwnership

Both ShareOwnership and GiveOwnership have identical implementations. If they are meant to be different operations, the implementation should reflect that. Otherwise, consider consolidating them.

The third parameter true in both calls to resource.ShareOwnership suggests keeping permissions. Should GiveOwnership pass false to transfer ownership without retaining permissions?


170-170: Consistent updates to DiscoverResource calls

All calls to DiscoverResource have been properly updated to include the new sourceId parameter, maintaining consistency with the enhanced authorization model.

Also applies to: 329-329, 369-369

Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
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: 1

🧹 Nitpick comments (1)
src/State/Attributes/DenyAnyOperation.php (1)

31-39: Consider adding parameter validation.

Unlike AllowCreateFrom which validates that at least one parameter is provided, this attribute accepts all null parameters, which would create a meaningless deny rule.

 public function __construct(
     public ?string $fromType = null,
     public EntityId|OrchestrationInstance|null $fromId = null,
     public ?string $fromUser = null,
     public ?string $fromRole = null,
-) {}
+) {
+    if ($fromType === null && $fromId === null && $fromUser === null && $fromRole === null) {
+        throw new \LogicException('At least one parameter must be provided to DenyAnyOperation');
+    }
+}

Also consider if AllowAnyOperation needs similar validation for consistency.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 9093267 and a3b2a09.

📒 Files selected for processing (26)
  • cli/auth/resource.go (6 hunks)
  • cli/auth/resourceManager.go (3 hunks)
  • cli/glue/glue.go (4 hunks)
  • cli/ids/id.go (3 hunks)
  • cli/lib/api.go (12 hunks)
  • cli/lib/consumer.go (11 hunks)
  • src/Contexts/AuthContext.php (1 hunks)
  • src/Contexts/AuthContext/SecurityException.php (1 hunks)
  • src/Contexts/AuthContext/functions.php (2 hunks)
  • src/Glue/glue.php (5 hunks)
  • src/State/AbstractHistory.php (4 hunks)
  • src/State/ActivityHistory.php (3 hunks)
  • src/State/Attributes/AccessControl.php (1 hunks)
  • src/State/Attributes/AllowAnyOperation.php (1 hunks)
  • src/State/Attributes/AllowCreateAll.php (1 hunks)
  • src/State/Attributes/AllowCreateForAuth.php (1 hunks)
  • src/State/Attributes/AllowCreateForRole.php (1 hunks)
  • src/State/Attributes/AllowCreateForUser.php (1 hunks)
  • src/State/Attributes/AllowCreateFrom.php (1 hunks)
  • src/State/Attributes/DenyAnyOperation.php (1 hunks)
  • src/State/EntityHistory.php (5 hunks)
  • src/State/Ids/StateId.php (0 hunks)
  • src/Task.php (1 hunks)
  • tests/Unit/ActivityHistoryTest.php (2 hunks)
  • tests/Unit/EntityHistoryTest.php (4 hunks)
  • tests/Unit/LockIntegrationTest.php (2 hunks)
💤 Files with no reviewable changes (1)
  • src/State/Ids/StateId.php
✅ Files skipped from review due to trivial changes (6)
  • src/State/Attributes/AccessControl.php
  • src/Contexts/AuthContext/SecurityException.php
  • src/Contexts/AuthContext/functions.php
  • src/Task.php
  • src/State/Attributes/AllowAnyOperation.php
  • src/Contexts/AuthContext.php
🚧 Files skipped from review as they are similar to previous changes (6)
  • cli/lib/api.go
  • cli/auth/resourceManager.go
  • cli/lib/consumer.go
  • src/Glue/glue.php
  • cli/ids/id.go
  • cli/auth/resource.go
🧰 Additional context used
🧬 Code Graph Analysis (7)
tests/Unit/ActivityHistoryTest.php (3)
src/State/EntityId.php (2)
  • from (42-45)
  • EntityId (33-51)
src/State/Ids/StateId.php (1)
  • fromEntityId (67-70)
src/functions.php (1)
  • EntityId (13-16)
src/State/Attributes/AllowCreateForRole.php (4)
src/State/Attributes/AllowCreateAll.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateForUser.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateFrom.php (1)
  • Attribute (11-28)
src/State/Attributes/AllowCreateForAuth.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateFrom.php (7)
src/State/Attributes/AllowAnyOperation.php (2)
  • Attribute (9-18)
  • __construct (12-17)
src/State/Attributes/AllowCreateAll.php (2)
  • Attribute (29-33)
  • __construct (32-32)
src/State/Attributes/AllowCreateForRole.php (2)
  • Attribute (29-33)
  • __construct (32-32)
src/State/Attributes/AllowCreateForUser.php (2)
  • Attribute (29-33)
  • __construct (32-32)
src/State/Attributes/AllowCreateForAuth.php (2)
  • Attribute (29-33)
  • __construct (32-32)
src/State/Attributes/DenyAnyOperation.php (2)
  • Attribute (31-40)
  • __construct (34-39)
cli/ids/id.go (1)
  • EntityId (144-147)
src/State/Attributes/AllowCreateForUser.php (11)
src/State/Attributes/AllowAnyOperation.php (1)
  • Attribute (9-18)
src/State/Attributes/AllowCreateAll.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateForRole.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateFrom.php (1)
  • Attribute (11-28)
src/State/Attributes/AllowCreateForAuth.php (1)
  • Attribute (29-33)
src/State/Attributes/DenyAnyOperation.php (1)
  • Attribute (31-40)
src/Events/Shares/NeedsSource.php (1)
  • Attribute (27-31)
src/Events/Shares/NeedsTarget.php (1)
  • Attribute (27-31)
src/Proxy/Pure.php (1)
  • Attribute (30-31)
src/State/Attributes/EntryPoint.php (1)
  • Attribute (27-28)
src/State/Attributes/Operation.php (1)
  • Attribute (27-31)
src/State/Attributes/AllowCreateAll.php (5)
src/State/Attributes/AllowCreateForRole.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateForUser.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateFrom.php (1)
  • Attribute (11-28)
src/State/Attributes/AllowCreateForAuth.php (1)
  • Attribute (29-33)
tests/Common/LauncherEntity.php (1)
  • AllowCreateAll (32-46)
src/State/Attributes/AllowCreateForAuth.php (11)
src/State/Attributes/AllowAnyOperation.php (1)
  • Attribute (9-18)
src/State/Attributes/AllowCreateAll.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateForRole.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateForUser.php (1)
  • Attribute (29-33)
src/State/Attributes/AllowCreateFrom.php (1)
  • Attribute (11-28)
src/State/Attributes/DenyAnyOperation.php (1)
  • Attribute (31-40)
src/Events/Shares/NeedsSource.php (1)
  • Attribute (27-31)
src/Events/Shares/NeedsTarget.php (1)
  • Attribute (27-31)
src/Proxy/Pure.php (1)
  • Attribute (30-31)
src/State/Attributes/EntryPoint.php (1)
  • Attribute (27-28)
src/State/Attributes/Operation.php (1)
  • Attribute (27-31)
src/State/Attributes/DenyAnyOperation.php (5)
src/State/Attributes/AllowAnyOperation.php (2)
  • Attribute (9-18)
  • __construct (12-17)
src/State/Attributes/AllowCreateForRole.php (2)
  • Attribute (29-33)
  • __construct (32-32)
src/State/Attributes/AllowCreateForUser.php (2)
  • Attribute (29-33)
  • __construct (32-32)
src/State/Attributes/AllowCreateFrom.php (2)
  • Attribute (11-28)
  • __construct (19-27)
cli/ids/id.go (1)
  • EntityId (144-147)
🪛 PHPMD (2.15.0)
src/State/AbstractHistory.php

67-67: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


67-67: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


77-77: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


77-77: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


82-82: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


82-82: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


87-87: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


87-87: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


92-92: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


92-92: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


97-97: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


97-97: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


102-102: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


102-102: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


107-107: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


107-107: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)

⏰ 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). (2)
  • GitHub Check: build-docker
  • GitHub Check: Unit Tests - PHP
🔇 Additional comments (19)
tests/Unit/ActivityHistoryTest.php (1)

68-68: LGTM! Proper provenance tracking setup.

The addition of the from property assignment correctly establishes provenance information for the test scenario, aligning with the PR's objective to add "from capability" for tracking event origins.

tests/Unit/LockIntegrationTest.php (2)

29-29: LGTM! Necessary imports for provenance tracking.

The imports for StateId and OrchestrationInstance are correctly added to support the new provenance functionality.

Also applies to: 32-32


54-54: LGTM! Consistent provenance setup.

The from property assignment properly establishes the orchestration instance as the source for this entity, maintaining consistency with the broader provenance tracking implementation.

tests/Unit/EntityHistoryTest.php (1)

64-64: LGTM! Comprehensive provenance tracking in all test scenarios.

The from property assignments are consistently applied across all three test cases (signal processing, locked events, and lock chaining), ensuring proper test coverage for the new provenance tracking functionality.

Also applies to: 88-88, 141-141

src/State/Attributes/AllowCreateForRole.php (2)

27-27: LGTM! Clean import organization.

Adding the explicit Attribute import improves code readability and follows PHP best practices.


29-30: LGTM! Consistent access control attribute pattern.

The changes align AllowCreateForRole with the unified access control system:

  • Simplified attribute declaration using only IS_REPEATABLE flag (consistent with AllowCreateFrom)
  • Implementation of AccessControl interface for unified access control handling
  • readonly modifier for immutability (consistent with AllowCreateForAuth)
src/State/Attributes/AllowCreateForUser.php (2)

27-27: LGTM! Clean import organization.

Adding the explicit Attribute import improves code readability and follows PHP best practices.


29-30: LGTM! Consistent access control attribute pattern.

The changes align AllowCreateForUser with the unified access control system:

  • Simplified attribute declaration using only IS_REPEATABLE flag (consistent with AllowCreateForRole and AllowCreateFrom)
  • Implementation of AccessControl interface for unified access control handling
src/State/ActivityHistory.php (3)

27-27: LGTM!

The new imports are properly organized and correctly used for the access control implementation.

Also applies to: 39-39, 45-45


91-95: LGTM!

The access control check for callable tasks is correctly implemented using reflection to retrieve AccessControl attributes and properly throws a SecurityException with contextual information when access is denied.


99-108: Refactor access control checks for better efficiency and debugging.

The current implementation performs duplicate work and has identical error messages. Consider:

  1. The entrypoint location (Line 104) happens even if class-level access is denied
  2. Both error messages are identical, making debugging difficult
 $task = $this->container->get($task);
 $reflection = new ReflectionClass($task);
 $attrs = $reflection->getAttributes(AccessControl::class, ReflectionAttribute::IS_INSTANCEOF);
 if (! $this->checkAccessControl($this->user, $this->from, ...$attrs)) {
-    throw new SecurityException(sprintf('Access denied to activity %s', $this->activityId));
+    throw new SecurityException(sprintf('Access denied to activity %s (class-level)', $this->activityId));
 }
 $entrypoint = $this->locateEntrypoint($reflection) ?? throw new RuntimeException("Unable to locate entrypoint for {$event->name}");
 $attrs = $entrypoint->getAttributes(AccessControl::class, ReflectionAttribute::IS_INSTANCEOF);
 if (! $this->checkAccessControl($this->user, $this->from, ...$attrs)) {
-    throw new SecurityException(sprintf('Access denied to activity %s', $this->activityId));
+    throw new SecurityException(sprintf('Access denied to activity %s (method-level)', $this->activityId));
 }

Likely an incorrect or invalid review comment.

src/State/Attributes/AllowCreateAll.php (1)

27-30: Verify the removal of TARGET_CLASS restriction is intentional.

The attribute declaration changed from #[\Attribute(\Attribute::TARGET_CLASS)] to #[Attribute], making it applicable to any target (methods, properties, etc.) rather than just classes. This seems inconsistent with the attribute name "AllowCreateAll" which implies class-level authorization.

Consider whether this attribute should maintain the TARGET_CLASS restriction or if the broader applicability is intentional. If broader usage is intended, document the valid targets.

src/State/Attributes/AllowCreateForAuth.php (1)

27-30: LGTM!

The changes properly align this attribute with the access control framework. The readonly modifier ensures immutability of the configuration.

src/State/Attributes/AllowCreateFrom.php (1)

11-27: Well-designed access control attribute!

The implementation correctly enforces mutual exclusivity between type and ID parameters, provides clear error messages, and uses proper type constraints. The repeatable attribute allows for flexible configuration of multiple allowed sources.

cli/glue/glue.go (1)

76-76: LGTM! Provenance tracking properly integrated.

The addition of the from parameter and its propagation through the glue layer is implemented correctly. The DPHP_SOURCE header appropriately transmits the source StateId to the PHP backend.

Also applies to: 106-106, 115-115, 129-129

src/State/EntityHistory.php (2)

210-213: Well-structured access control implementation.

The multi-level access control checks (class, property, and method) provide comprehensive security coverage. The consistent use of checkAccessControl method and appropriate exception handling ensures proper authorization enforcement.

Also applies to: 257-259


230-231: PHP 8.4 property hooks are supported
The project’s composer.json specifies "php": ">=8.4", so using PropertyHookType::Get and PropertyHookType::Set is fully compatible. No changes required.

src/State/AbstractHistory.php (2)

144-217: Comprehensive access control implementation.

The checkAccessControl method provides a well-structured evaluation of various access control attributes. The logic correctly handles different permission scenarios and follows a clear precedence order.

A few observations:

  • The method returns true when no access controls are defined (line 148), delegating to runtime checks
  • AllowCreateAll immediately grants access (line 154)
  • Deny rules are evaluated last and can override allow rules
  • The default return is false (line 216), following a secure-by-default approach

54-57: Proper configuration of the $from property.

The $from property is correctly marked with #[Field(exclude: true)] to prevent serialization, which is appropriate for runtime provenance tracking that shouldn't be persisted with the state.

Signed-off-by: Robert Landers <landers.robert@gmail.com>
Signed-off-by: Robert Landers <landers.robert@gmail.com>
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: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 5b811d5 and 90d1d93.

📒 Files selected for processing (2)
  • src/State/AbstractHistory.php (4 hunks)
  • tests/Unit/AbstractHistoryTest.php (1 hunks)
🧰 Additional context used
🪛 PHPMD (2.15.0)
tests/Unit/AbstractHistoryTest.php

46-46: Avoid unused parameters such as '$logger'. (Unused Code Rules)

(UnusedFormalParameter)


46-46: Avoid unused parameters such as '$user'. (Unused Code Rules)

(UnusedFormalParameter)


62-62: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


67-67: Avoid unused parameters such as '$logger'. (Unused Code Rules)

(UnusedFormalParameter)


72-72: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)

src/State/AbstractHistory.php

67-67: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


67-67: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


77-77: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


77-77: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


82-82: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


82-82: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


87-87: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


87-87: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


92-92: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


92-92: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


97-97: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


97-97: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


102-102: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


102-102: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)


107-107: Avoid unused parameters such as '$event'. (Unused Code Rules)

(UnusedFormalParameter)


107-107: Avoid unused parameters such as '$original'. (Unused Code Rules)

(UnusedFormalParameter)

⏰ 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). (2)
  • GitHub Check: build-docker
  • GitHub Check: Unit Tests - PHP
🔇 Additional comments (5)
tests/Unit/AbstractHistoryTest.php (3)

42-77: LGTM! Test implementation is appropriate.

The TestableAbstractHistory class correctly exposes the protected checkAccessControl method for testing. The unused parameter warnings from static analysis are false positives since these methods must match the abstract interface signatures.


80-110: Well-designed test helper function.

The createAttribute function cleverly creates mock ReflectionAttribute instances for testing without requiring actual PHP attributes. The dynamic instantiation correctly handles attribute arguments.


113-416: Comprehensive test coverage for access control.

The test suite thoroughly covers all access control scenarios:

  • All attribute types (AllowCreateAll, AllowCreateForAuth, AllowCreateForRole, AllowCreateForUser, AllowCreateFrom, AllowAnyOperation, DenyAnyOperation)
  • Edge cases (null users, empty roles, no matches)
  • Complex scenarios (multiple attributes, deny overriding allow)

The tests effectively validate the access control logic implemented in AbstractHistory::checkAccessControl().

src/State/AbstractHistory.php (2)

54-57: Property additions look good.

The explicit nullable type for $status improves clarity, and the new $from property appropriately tracks state origin with serialization exclusion.


144-221: Align PHP version requirements and improve condition readability

The project’s root composer.json already requires PHP ≥8.4 (so array_any() is available), but there’s a secondary composer.json set to PHP ≥8.3. Please ensure all composer.json files target PHP 8.4+ or supply a polyfill for array_any() to avoid runtime errors.

Separately, the combined isEntityId()/toEntityId()->name and isOrchestrationId()/toOrchestrationInstance()->instanceId checks on lines 166 and 214 are hard to follow. Consider extracting those blocks into named methods, for example:

  • private function matchesFromId(StateId $from, mixed $id): bool
  • private function matchesFromType(StateId $from, string $type): bool

This will make the deny/allow flow in checkAccessControl() much clearer.

@withinboredom withinboredom merged commit d3d56d4 into v2 Aug 3, 2025
6 checks passed
@withinboredom withinboredom deleted the add/from branch August 3, 2025 00: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.

2 participants