mirror of
https://github.com/PerpetualSoftware/pad.git
synced 2026-11-01 17:09:55 +00:00
37066f97be
* feat(apps): app attachment routes: item-scoped upload, metadata and a streamed download re-admitted before its first byte (TASK-3401, SPEC-6 U6c) * test(server): an app attachment read refuses a subject whose membership no longer reaches the item (TASK-3401, U6c) * test(server): U6c tests reach the item re-check, the upload's edit right and the download's type decision (TASK-3401, U6c) * test(server): a deletion before the first byte reaches the attachment re-check (TASK-3401, U6c) * fix(apps): U6c codex r1: authorize before storage, a transport write deadline, the credential last in re-admission, and a live companion check in the fence (TASK-3401, U6c) * fix(apps): U6c codex r2: a truncated upload is 400, a re-admission fault is 500 not 401, HEAD on the download, and unknown variants refused (TASK-3401, U6c) * fix(apps): U6c codex r3: the upload re-admits the subject before its row (StageUpload/Insert, no store callback), and variant is null on originals (TASK-3401, U6c) * fix(apps): U6c codex r4: a token-state or settings read failure during admission is a fault (500), not a denial (TASK-3401, U6c) * fix(apps): U6c codex r5: a credential that dies mid-upload answers 401 invalid_token, a permission change 403 (TASK-3401, U6c) * fix(apps): U6c codex r6: the served variant is re-checked at the gate, and a settings read fault at the first gate is a 500 (TASK-3401, U6c) * test(server): a viewer's upload is refused before its body is read (TASK-3401, U6c) * test(server): account for the app upload's raw body reader in the body-reader census (TASK-3401, U6c)
43 lines
1.5 KiB
Go
43 lines
1.5 KiB
Go
package server
|
|
|
|
import "log/slog"
|
|
|
|
// Whether installed apps are available on this server (SPEC-6, DOC-3371 §9;
|
|
// Dave's day-85 answer Q1). Shared by U8 (the install routes) and U5 (the
|
|
// token and introspection endpoints for install clients), which must agree
|
|
// exactly, so it lives alone in this file.
|
|
|
|
// settingAppsEnabled is the platform_settings key an instance admin turns on.
|
|
// Self-host default is off: an unset key reads as off.
|
|
const settingAppsEnabled = "apps_enabled"
|
|
|
|
// appsAvailable: Pad Cloud always; self-host only when an admin has enabled
|
|
// apps AND the server has an OAuth server with an https issuer, since every
|
|
// app credential is an OAuth token. It does not depend on the MCP setting.
|
|
// A settings read error counts as off: the capability fails closed.
|
|
func (s *Server) appsAvailable() bool {
|
|
on, err := s.appsAvailableChecked()
|
|
if err != nil {
|
|
slog.Warn("apps: reading the apps_enabled setting failed; treating apps as off", "error", err)
|
|
return false
|
|
}
|
|
return on
|
|
}
|
|
|
|
// appsAvailableChecked is appsAvailable with a failure to read the setting
|
|
// reported rather than folded into "off", for re-admission, where a fault
|
|
// must not read as a revocation (TASK-3401 U6c codex r4).
|
|
func (s *Server) appsAvailableChecked() (bool, error) {
|
|
if s.cloudMode {
|
|
return s.oauthServer != nil, nil
|
|
}
|
|
if s.oauthServer == nil || !s.mcpEndpoints.HTTPS() {
|
|
return false, nil
|
|
}
|
|
v, err := s.store.GetPlatformSetting(settingAppsEnabled)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
return v == "true", nil
|
|
}
|