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:
@@ -217,7 +217,7 @@ pub async fn build_app(pool: PgPool, auth: AuthDeps) -> anyhow::Result<Router> {
|
||||
};
|
||||
let route_admin = RouteAdminState {
|
||||
routes: route_repo.clone(),
|
||||
scripts: Arc::new(PostgresScriptRepoHandle(script_repo)),
|
||||
scripts: Arc::new(PostgresScriptRepoHandle(script_repo.clone())),
|
||||
domains: domains_repo.clone(),
|
||||
table: route_table.clone(),
|
||||
authz: authz.clone(),
|
||||
@@ -245,6 +245,7 @@ pub async fn build_app(pool: PgPool, auth: AuthDeps) -> anyhow::Result<Router> {
|
||||
triggers: trigger_repo,
|
||||
apps: apps_repo.clone(),
|
||||
authz: authz.clone(),
|
||||
scripts: Arc::new(PostgresScriptRepoHandle(script_repo.clone())),
|
||||
config: trigger_config,
|
||||
};
|
||||
let dead_letters_state = DeadLettersState {
|
||||
|
||||
Reference in New Issue
Block a user