Skip to content

Commit

Permalink
i/prompting/requestprompts: include reason in notice data when prompt…
Browse files Browse the repository at this point in the history
… resolved

A prompt may only be resolved once, and the notice recorded when that
prompt is resolved is the final notice which will be associated with
that prompt ID. Therefore, it is safe to include notice data without
risk of signal loss.

Currently, prompt clients need to query the prompting API in order to
check whether an outstanding prompt was modified (due to some but not
all of its permissions being satisfied by a new rule) or fully resolved,
either due to a direct reply, a new rule satisfying all remaining
permissions, or the prompt DB being closed.

Since the notice recorded when a prompt is resolved is the final notice
for that prompt, we can instead include the "resolved" key in the
notice data to indicate to the client that the prompt has been resolved
without the need to query the prompting API. And the value for the
"resolved" key can be "replied", "satisfied", or "cancelled", giving
additional information to the prompt client about why the prompt was
resolved.

Signed-off-by: Oliver Calder <[email protected]>
  • Loading branch information
olivercalder committed Jun 6, 2024
1 parent 9a6adfe commit 3afec64
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 48 deletions.
21 changes: 14 additions & 7 deletions interfaces/prompting/requestprompts/requestprompts.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,15 @@ type PromptDB struct {
maxIDPath string
mutex sync.Mutex
// Function to issue a notice for a change in a prompt
notifyPrompt func(userID uint32, promptID string) error
notifyPrompt func(userID uint32, promptID string, data map[string]string) error
}

// New creates and returns a new prompt database.
//
// The given notifyPrompt closure should record a notice of type
// "interfaces-requests-prompt" for the given user with the given
// promptID as its key.
func New(notifyPrompt func(userID uint32, promptID string) error) *PromptDB {
func New(notifyPrompt func(userID uint32, promptID string, data map[string]string) error) *PromptDB {
pdb := PromptDB{
perUser: make(map[uint32]*userPromptDB),
notifyPrompt: notifyPrompt,
Expand Down Expand Up @@ -212,7 +212,7 @@ func (pdb *PromptDB) AddOrMerge(metadata *prompting.Metadata, path string, permi
// have replied with a malformed response and not retried after
// receiving the error, so this notice encourages it to try again
// if the user retries the operation.
pdb.notifyPrompt(metadata.User, prompt.ID)
pdb.notifyPrompt(metadata.User, prompt.ID, nil)
return prompt, true
}
}
Expand All @@ -228,7 +228,7 @@ func (pdb *PromptDB) AddOrMerge(metadata *prompting.Metadata, path string, permi
listenerReqs: []*listener.Request{listenerReq},
}
userEntry.ByID[id] = prompt
pdb.notifyPrompt(metadata.User, id)
pdb.notifyPrompt(metadata.User, id, nil)
return prompt, false
}

Expand Down Expand Up @@ -293,7 +293,9 @@ func (pdb *PromptDB) Reply(user uint32, id string, outcome prompting.OutcomeType
}
}
delete(userEntry.ByID, id)
pdb.notifyPrompt(user, id)
data := make(map[string]string)
data["resolved"] = "replied"
pdb.notifyPrompt(user, id, data)
return prompt, nil
}

Expand Down Expand Up @@ -344,8 +346,8 @@ func (pdb *PromptDB) HandleNewRule(metadata *prompting.Metadata, constraints *pr
if !modified {
continue
}
pdb.notifyPrompt(metadata.User, id)
if len(prompt.Constraints.Permissions) > 0 && allow == true {
pdb.notifyPrompt(metadata.User, id, nil)
continue
}
// All permissions of prompt satisfied, or any permission denied
Expand All @@ -354,6 +356,9 @@ func (pdb *PromptDB) HandleNewRule(metadata *prompting.Metadata, constraints *pr
}
delete(userEntry.ByID, id)
satisfiedPromptIDs = append(satisfiedPromptIDs, id)
data := make(map[string]string)
data["resolved"] = "satisfied"
pdb.notifyPrompt(metadata.User, id, data)
}
return satisfiedPromptIDs, nil
}
Expand All @@ -363,11 +368,13 @@ func (pdb *PromptDB) HandleNewRule(metadata *prompting.Metadata, constraints *pr
// This should be called when snapd is shutting down, to notify prompt clients
// that the given prompts are no longer awaiting a reply.
func (pdb *PromptDB) Close() {
data := make(map[string]string)
data["resolved"] = "cancelled"
pdb.mutex.Lock()
defer pdb.mutex.Unlock()
for user, userEntry := range pdb.perUser {
for id := range userEntry.ByID {
pdb.notifyPrompt(user, id)
pdb.notifyPrompt(user, id, data)
}
}
// Clear all outstanding prompts
Expand Down
Loading

0 comments on commit 3afec64

Please sign in to comment.