mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-09-04 06:35:29 +00:00
feat: add Apprise as a fourth notification channel (#1644)
* feat: add Apprise as a fourth notification channel Support keyed and stateless Apprise endpoints with secret-safe public DTOs, fail-closed malformed config, and mode-specific Settings UI. Docs and screenshots updated for four-channel Channels and routing. * fix: harden Apprise secrets at rest and preserve-on-write saves Encrypt Apprise endpoint and config with CryptoService so a downgrade cannot leak via SELECT *. Align channel and routing saves so blank destination fields omit config on same-mode URL edits, enforce keyed notify IDs, and keep secrets_redacted truthful. * fix: harden Apprise route type changes and mixed-version config UI Require a raw channel_url when switching notification-route types so ciphertext cannot strand under Discord/Slack/webhook. Default missing remote apprise status, replace Channels state on node switch, and exercise the production config-column migrator. * fix: tolerate stub fleet configuration payloads without agents Normalize remote Apprise agent status only when notifications.agents is present so successful Pilot/stub fetches stay online instead of throwing into the offline catch path. * fix: correct TypeScript in configuration normalize tests * fix: ignore stale Channels agent bodies after node switch Compare the active node after response JSON parsing so a slow body cannot overwrite the newly selected node's channel state. * fix: isolate corrupt Apprise crypto and keep keyed Tags visible Decrypt failures on one Apprise row no longer 500 agent/route lists or suppress sibling channel dispatch. Treat public /notify/<redacted> as keyed so Tags remain editable after reload.
This commit is contained in:
@@ -108,4 +108,29 @@ describe('conditionalJsonParser remote-proxy bypass', () => {
|
||||
expect(lastUpstreamAuth).toBeNull();
|
||||
expect([200, 404]).toContain(res.status);
|
||||
});
|
||||
|
||||
it('forwards Apprise agent config bodies intact to the remote', async () => {
|
||||
lastUpstreamBody = null;
|
||||
lastUpstreamAuth = null;
|
||||
|
||||
const payload = {
|
||||
type: 'apprise',
|
||||
url: 'http://apprise.local/notify',
|
||||
enabled: true,
|
||||
config: { urls: 'discord://webhook-id/webhook-token?token=query-secret' },
|
||||
};
|
||||
|
||||
const res = await request(app)
|
||||
.post('/api/agents')
|
||||
.set('Authorization', authHeader)
|
||||
.set('x-node-id', String(remoteNodeId))
|
||||
.set('Content-Type', 'application/json')
|
||||
.send(payload);
|
||||
|
||||
expect(res.status).toBe(200);
|
||||
expect(lastUpstreamBody).not.toBeNull();
|
||||
expect(JSON.parse(lastUpstreamBody!.toString('utf-8'))).toEqual(payload);
|
||||
expect(lastUpstreamAuth).toBe('Bearer bypass-test-token');
|
||||
expect(JSON.stringify(res.body)).not.toContain('query-secret');
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user