feat(v1.1.3-modules): reject module scripts from routes + triggers; tighten cross-app trigger check
- `POST /api/v1/admin/scripts/{id}/routes` returns 400 when the
target script is `kind=module`. Modules have no entry point — they
are imported, not invoked.
- `POST /api/v1/admin/apps/{id}/triggers/{kv,docs,dead_letter}` gain
a shared `validate_trigger_target` that loads the target script
and rejects when:
- the script doesn't exist
- the script belongs to a different app (latent v1.1.1/v1.1.2 gap
where triggers could target a script in any app — closed here)
- the script is `kind=module`
- `TriggersState` grows a `scripts: Arc<dyn ScriptRepository>` field
so handlers can load the target script.
- Trigger-create test helpers split into `state_with` (empty script
repo — for tests asserting upstream errors) and
`state_with_endpoint` (pre-populated — for tests asserting
successful creation). `InMemoryScriptRepo` added to the test
module.
Workspace builds; full test suite (~440 tests) green.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -184,6 +184,17 @@ async fn create_route<RR: RouteRepository, SR: ScriptRepository>(
|
||||
)
|
||||
.await?;
|
||||
|
||||
// v1.1.3: module scripts have no executable entry point — they're
|
||||
// libraries imported by other scripts. Reject route bindings here
|
||||
// before we touch the routes table.
|
||||
if script.kind == picloud_shared::ScriptKind::Module {
|
||||
return Err(RouteApiError::BadRequest(format!(
|
||||
"script {script_id} has kind=module; modules are imported, \
|
||||
not bound to routes — switch the script to kind=endpoint \
|
||||
or attach this route to a different script"
|
||||
)));
|
||||
}
|
||||
|
||||
// Validate the route's host is consistent with one of the app's
|
||||
// domain claims. `HostKind::Any` is always permitted (catches every
|
||||
// host the app already owns). Specific hosts must match a claim.
|
||||
|
||||
Reference in New Issue
Block a user