Skip to content

Govstack API: filter work orders and runs via REST API by UUIDs or status#4553

Open
taylordowns2000 wants to merge 3 commits intomainfrom
govstack-api
Open

Govstack API: filter work orders and runs via REST API by UUIDs or status#4553
taylordowns2000 wants to merge 3 commits intomainfrom
govstack-api

Conversation

@taylordowns2000
Copy link
Copy Markdown
Member

Description

This PR closes #4552 by adding tests for the show case on the work order REST API and adding the ability to pass a list of IDs into the index case on the work order REST API.

Validation steps

  1. Create an API token
  2. Go to a project that has a few workorders
  3. Try curling for those workorders like this
curl ...

AI Usage

Please disclose whether you've used AI anywhere in this PR (it's cool, we just
want to know!):

  • I have used Claude Code
  • I have used another model
  • I have not used AI

You can read more details in our
Responsible AI Policy

Pre-submission checklist

  • I have performed an AI review of my code (we recommend using /review
    with Claude Code)
  • I have implemented and tested all related authorization policies.
    (e.g., :owner, :admin, :editor, :viewer)
  • I have updated the changelog.
  • I have ticked a box in "AI usage" in this PR

@github-project-automation github-project-automation bot moved this to New Issues in Core Mar 23, 2026
@taylordowns2000
Copy link
Copy Markdown
Member Author

Code Review: Work Orders API — ID Filter & Show Action

Overview

Three files changed: added an id filter to the work orders query pipeline, fixed the show action to handle non-existent records, and added tests for both.


1. Status Codes: 401 vs 403

Finding: 401 is consistent with the codebase, but technically wrong per HTTP spec.

The chain works like this:

  • Permissions.can/4 always returns {:error, :unauthorized} on policy failure
  • FallbackController maps {:error, :unauthorized} → HTTP 401
  • FallbackController maps {:error, :forbidden} → HTTP 403

Every API controller (RunController, JobController, ProjectController) follows this same pattern and returns 401 when an authenticated user tries to access a resource in a project they don't belong to. The only exception is CredentialController, which explicitly intercepts {:error, :unauthorized} and re-maps it to {:error, :forbidden} → 403.

Per RFC 7235, 401 means "not authenticated" and 403 means "authenticated but not authorized". The entire API layer has this backwards — but our test asserting 401 is consistent with the existing pattern. This is a pre-existing issue, not something introduced by this PR. If you want to fix it platform-wide, that's a separate effort.


2. Authorization Policies

Finding: Authorization is correct. The id filter cannot bypass access controls.

index (non-project-scoped): The base query work_orders_for(%User{}) inner-joins against the user's own projects via a subquery on project_users. The id filter adds a WHERE wo.id IN (...) on top of that already-scoped query. If someone passes a UUID for a work order in a project they don't belong to, the inner join eliminates it — they get an empty result, not the data.

index (project-scoped): Explicitly calls Permissions.can(:access_project, ...) before fetching any data.

show: Preloads workflow.project and calls Permissions.can(:access_project, ...). Non-existent IDs now correctly return 404 (the bug fix in this PR).

Role coverage: The :access_project policy (project_users.ex:52) grants access to any project member regardless of role (owner, admin, editor, viewer). Since work orders are read-only (:index and :show only in the router), this is appropriate — all members should be able to view execution status.

One gap worth noting: There is no test for the show action via the nested route (/api/projects/:project_id/work_orders/:id). The router defines both routes, but the show test only exercises the top-level route. This is low risk since both routes hit the same controller action.


3. Regression Risk Analysis

Risk: Very Low

Change Risk Reasoning
filter_work_orders_by_ids/2 added to query pipeline Minimal nil clause is a no-op; only activates when id param is present. Existing queries without id are unchanged.
show action nil-guard Positive This fixes a crash (KeyError on nil.workflow). No existing behavior changes for valid IDs.
Test additions None Purely additive.

No impact on:

  • Other API endpoints (the filter function is only called from WorkOrdersController)
  • The LiveView work order pages (they use different query paths)
  • Background job processing (Oban workers don't use this query)
  • The validate_datetime_params flow (untouched)

One minor code quality note: The id filter accepts arbitrary strings without UUID validation. Passing a non-UUID string like ?id=notauuid would hit Postgres with an invalid UUID cast and raise an Ecto error. The existing project_id and workflow_id filters have the same behavior, so this is consistent — but worth being aware of if you want to add input validation later.


Summary

  • 401 is the established pattern — technically should be 403, but changing it here alone would be inconsistent. Flag for a future platform-wide fix if desired.
  • Authorization is secure — the id filter cannot leak data across project boundaries.
  • The show nil-guard is a genuine bug fix — the pre-existing code would crash on non-existent IDs.
  • Regression risk is very low — all changes are additive or defensive.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 23, 2026

Codecov Report

❌ Patch coverage is 95.65217% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.64%. Comparing base (3fe81d8) to head (63ca088).

Files with missing lines Patch % Lines
lib/lightning/runs/run.ex 0.00% 1 Missing ⚠️
lib/lightning/workorders/workorder.ex 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4553      +/-   ##
==========================================
+ Coverage   89.49%   89.64%   +0.15%     
==========================================
  Files         441      441              
  Lines       21249    21282      +33     
==========================================
+ Hits        19017    19079      +62     
+ Misses       2232     2203      -29     

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@taylordowns2000 taylordowns2000 marked this pull request as ready for review March 23, 2026 09:18
@midigofrank midigofrank changed the title close #4552 Govstack API: filter by many IDs Mar 27, 2026
@midigofrank midigofrank changed the title Govstack API: filter by many IDs Govstack API: filter work orders and runs via REST API by UUIDs or status Mar 27, 2026
@midigofrank midigofrank requested a review from stuartc March 27, 2026 06:40
taylordowns2000 and others added 2 commits March 31, 2026 16:33
…rdcoding

Expose Run.states/0 and WorkOrder.states/0 as public functions so
consumers derive valid states from the schema rather than duplicating
them. Update Invocation.Query to use these functions instead of
hardcoded ~w() lists. Remove duplicate curl example comments from
API controller test files (canonical versions remain in controller
moduledocs).
@stuartc stuartc self-requested a review March 31, 2026 15:20
Copy link
Copy Markdown
Member

@stuartc stuartc left a comment

Choose a reason for hiding this comment

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

Please resolve the duplicate test files for the controller, LightningWeb.API.WorkflowsControllerTest.

And trim or remove the curl examples in the tests. My opinion is that they are noise, happy to keep them if you don't agree.

@github-project-automation github-project-automation bot moved this from New Issues to In review in Core Mar 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In review

Development

Successfully merging this pull request may close these issues.

GovStack API - tests for show and filter by many IDs

3 participants