Lines 1-30javascript
2 * This file is part of Plum.
4 * Plum is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Plum is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Plum. If not, see https://www.gnu.org/licenses/.
18import{h as As,a as i,t as _,s as p,e as Me,b as O,c as we,n as tt}from"../chunks/ll-VsEGv.js";import{i as Is}from"../chunks/DGryW1Vp.js";import{p as Ts,m as o,o as js,s as l,c as e,l as ka,b as Bs,f as ve,d as Ms,$ as Ls,j as a,k
19 links.</p></div> <div class="card settings-card svelte-9l533f"><p class="card-title">Webhooks</p> <div class="field"><label class="field-label svelte-9l533f" for="discord-url"><span>Discord Webhook URL</span> <span class="field-hint svelte-9l533f">Leave blank to disable Discord notifications</span></label> <input id="discord-url" type="url" class="field-input" placeholder="https://discord.com/api/webhooks/…"></div> <div class="field"><label class="field-label svelte-9l533f" for="slack-url"><span>Slack Webhook URL</span> <span class="field-hint svelte-9l533f">Leave blank to disable Slack ...
20 deployment) or any other external script by calling <code class="code-sample svelte-9l533f"></code> with an <code class="code-sample svelte-9l533f">Authorization: ApiKey …</code> header. Generate a key on the <button class="link-btn svelte-9l533f">MCP tab</button> and store it as a repo secret — never commit it directly. Runs triggered this way show up
21 in Reports tagged <!>.</p> <pre class="mcp-snippet svelte-9l533f"> </pre> <div class="card-footer svelte-9l533f"><!></div></div></div>`),Bl=_('<p class="content-desc svelte-9l533f">No key generated yet.</p> <div class="card-footer svelte-9l533f"><!></div>',1),Ml=tt('<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94"></path><path d="M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19"></p ...
22 etc.).</p> <pre class="mcp-snippet svelte-9l533f"> </pre> <div class="card-footer svelte-9l533f"><!></div></div>`),Dl=_(`<div class="content-section svelte-9l533f"><div class="content-header svelte-9l533f"><h2 class="svelte-9l533f">MCP Integration</h2> <p class="content-desc svelte-9l533f">Generate an API key for any MCP-compatible AI client — Claude, Cursor, Windsurf, and
23 others.</p></div> <div class="card settings-card svelte-9l533f"><p class="card-title">API Key</p> <!></div> <!></div>`),Wl=_('<p class="form-error svelte-9l533f"> </p>'),zl=_('<p class="form-error svelte-9l533f"> </p>'),Gl=_('<div class="content-section svelte-9l533f"><div class="content-header svelte-9l533f"><h2 class="svelte-9l533f">Account</h2> <p class="content-desc svelte-9l533f">Manage your profile, credentials and session.</p></div> <div class="card settings-card svelte-9l533f"><p class="card-title">Profile</p> <div class="field"><label class="field-label svelte-9l533f" for="profi ...
24 S3-compatible storage — Cloudflare R2, Backblaze B2, AWS S3, or MinIO.</p></div> <div class="card settings-card svelte-9l533f"><p class="card-title">Manual Backup</p> <div class="backup-row svelte-9l533f"><div class="backup-block svelte-9l533f"><p class="backup-block-title svelte-9l533f">Export</p> <p class="backup-block-desc svelte-9l533f">Downloads a <code class="svelte-9l533f">.json</code> file with all cron jobs, test cases, test runs, users,
25 runners, and project settings.</p> <!></div> <div class="backup-divider svelte-9l533f"></div> <div class="backup-block svelte-9l533f"><p class="backup-block-title svelte-9l533f">Import</p> <p class="backup-block-desc svelte-9l533f">Restores all data from a previously exported backup. Existing records are
26 overwritten. Cron jobs are re-scheduled after import.</p> <div class="import-row svelte-9l533f"><label class="file-label svelte-9l533f"><input type="file" accept=".json" class="file-input-hidden svelte-9l533f"> <span class="file-btn svelte-9l533f"> </span></label> <!></div></div></div> <p class="backup-disclaimer svelte-9l533f">Reports are not included in backups. To back up report history, run <code>pg_dump</code> directly on the PostgreSQL volume.</p></div> <div class="card settings-card svelte-9l533f"><p class="card-title">S3 Storage</p> <p class="backup-block-desc svelte-9l533f" st ...
CriticalCredential Exfiltration
Source appears to send environment or credential material to an external endpoint.
frontend/build/client/_app/immutable/nodes/8.BfUuob4H.jsView on unpkg · L14 27 Leave <strong>Endpoint URL</strong> empty for AWS S3.</p> <div class="field-row svelte-9l533f"><div class="field"><label class="field-label svelte-9l533f" for="s3-endpoint"><span>Endpoint URL</span> <span class="field-hint svelte-9l533f">Leave blank for AWS S3</span></label> <input id="s3-endpoint" type="url" class="field-input" placeholder="https://account.r2.cloudflarestorage.com"></div> <div class="field"><label class="field-label svelte-9l533f" for="s3-region"><span>Region</span> <span class="field-hint svelte-9l533f">Use <code>auto</code> for Cloudflare R2</span></label> <input id=" ...
28`))}),ka(()=>se(),()=>{var r;l($t,((r=se().user)==null?void 0:r.role)==="admin"?[{id:"project",label:"Project"},{id:"runners",label:"Runners"},{id:"repository",label:"Repository"},{id:"integrations",label:"Integrations"},{id:"mcp",label:"MCP"},{id:"account",label:"Account"},{id:"users",label:"Users"},{id:"backup",label:"Backup"}]:[{id:"account",label:"Account"}])}),Bs(),Is();var Rt=nr();As(r=>{Ls.title="Settings — Plum"});var Ut=ve(Rt);Ds(Ut,{get toast(){return e(nt)}});var Et=a(Ut,4),pt=s(Et),At=s(pt);ya(At,5,()=>e($t),Qa,(r,n)=>{var D=bl(),fe=s(D,!0);t(D),c(()=>{da(D,"active",e(pe)===e(n).id ...
29 ${e(Ha)??""}`)}),i(S,be)};P(hs,S=>{e(la)&&S(ks)})}t(Ae);var ft=a(Ae,2),ys=a(s(ft),2);{var ws=S=>{var be=er();i(S,be)},xs=S=>{var be=rr(),de=ve(be),Tt=s(de),_t=a(s(Tt),2);t(Tt),t(de);var bt=a(de,2),jt=a(s(bt),2);R(jt),t(bt);var Bt=a(bt,2);{var $s=Oe=>{var Aa=lr(),Ze=s(Aa),Ps=a(Ze);{var Cs=Qe=>{var De=ar(),gt=s(De);t(De),c(mt=>p(gt,`uploaded to ${mt??""}`),[()=>e(ze).replace("success:","")],ca),i(Qe,De)},Rs=Qe=>{var De=we(),gt=ve(De);{var mt=ha=>{var Be=tr(),ht=s(Be,!0);t(Be),c(Es=>p(ht,Es),[()=>e(ze).replace("error:","")],ca),i(ha,Be)},Us=ha=>{var Be=sr(),ht=s(Be,!0);t(Be),c(()=>p(ht,e(z ...
Long lines were clipped for display.