test(stateful-templates): group email template journey + load group secrets (M5.5)

CLI journey: set a group secret, apply a group [[triggers.email]] template
referencing it, create an app under the group → `pic triggers ls --app`
shows a materialized email trigger; re-apply is a NoOp.

Required loading a group's own set-secret names into CurrentState (was
hardcoded empty) so the apply plan-time email-secret check resolves the
ref against the GROUP store. Informational only — the secrets diff is
never executed on apply (secrets are set out-of-band via `pic secret
set`); the state token now folds in group secrets, matching apps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-07-02 20:29:23 +02:00
parent e2457efcbe
commit da83222ea1
2 changed files with 104 additions and 11 deletions

View File

@@ -2593,7 +2593,8 @@ impl ApplyService {
.list_for_app(app_id)
.await
.map_err(|e| ApplyError::Backend(e.to_string()))?,
self.all_secret_names(app_id).await?,
self.all_secret_names(crate::secrets_service::SecretOwner::App(app_id))
.await?,
VarOwner::App(app_id),
),
ApplyOwner::Group(group_id) => (
@@ -2611,7 +2612,12 @@ impl ApplyService {
.list_for_group(group_id)
.await
.map_err(|e| ApplyError::Backend(e.to_string()))?,
Vec::new(),
// §4.5 M5.5: a group's own set secrets — the plan check for an
// email TEMPLATE resolves `inbound_secret_ref` against the
// GROUP store, and the state token folds them in. Informational
// in the secrets diff only (apply never writes secrets).
self.all_secret_names(crate::secrets_service::SecretOwner::Group(group_id))
.await?,
VarOwner::Group(group_id),
),
};
@@ -2658,17 +2664,16 @@ impl ApplyService {
})
}
async fn all_secret_names(&self, app_id: AppId) -> Result<Vec<String>, ApplyError> {
async fn all_secret_names(
&self,
owner: crate::secrets_service::SecretOwner,
) -> Result<Vec<String>, ApplyError> {
let mut names = Vec::new();
let mut cursor: Option<String> = None;
loop {
let page = self
.secrets
.list_names(
crate::secrets_service::SecretOwner::App(app_id),
cursor.as_deref(),
200,
)
.list_names(owner, cursor.as_deref(), 200)
.await
.map_err(|e| ApplyError::Backend(e.to_string()))?;
names.extend(page.names);