Adds the integration layer that turns external sources into provenance-tagged observations without ever executing what it reads. - research folder poller: os.OpenRoot, text allowlist, binary/archive/symlink rejection, content fingerprints, duplicate tracking - git poller: bare shallow mirror with hooks disabled and ext protocol refused, commit observations, co-change pairs - Prometheus poller: threshold crossings and relative-change detection - webhooks: HMAC over timestamp.body, +/-300s window, replay cache, 256 KiB cap, per-IP rate limit; refused entirely without a secret - capabilities read_metrics (allow) and repository.read (ask), scoped to the invoking mind's integrations - migrations 0013, API, UI pages, noemactl integrations, docs/integrations.md
15 lines
3.3 KiB
HTML
15 lines
3.3 KiB
HTML
{{define "content"}}
|
||
{{$i := .Data.Integration}}
|
||
<div class="pagehead mindhead"><div><p class="muted small"><a href="/integrations">Integrations</a> › {{$i.Kind}}</p><h1>{{$i.Name}} <span class="badge is-{{$i.Status}}">{{$i.Status}}</span></h1><p class="muted">Mind {{.Data.MindName}} · trust {{$i.Trust}} · every {{$i.Interval}}{{if $i.SecretSet}} · secret set{{end}}{{with $i.LastError}} · <span class="danger">{{.}}</span>{{end}}</p></div>
|
||
<div class="row">{{if and (.Principal.User.Role.AtLeast "operator") (ne $i.Kind "webhook")}}<form method="post" action="/integrations/{{$i.ID}}/run"><input type="hidden" name="_csrf" value="{{.CSRF}}"><button class="btn">Run now</button></form>{{end}}
|
||
{{if .Principal.User.Role.AtLeast "administrator"}}<form method="post" action="/integrations/{{$i.ID}}/toggle"><input type="hidden" name="_csrf" value="{{.CSRF}}"><button class="btn">{{if $i.Enabled}}Disable{{else}}Enable{{end}}</button></form>
|
||
<form method="post" action="/integrations/{{$i.ID}}/delete"><input type="hidden" name="_csrf" value="{{.CSRF}}"><button class="btn btn-danger" data-confirm="Delete this integration? Ingested observations remain in history.">Delete</button></form>{{end}}</div></div>
|
||
<section class="grid cols-2">
|
||
<div class="card"><h2>Configuration</h2><pre class="json">{{pretty (jsonOf $i.Config)}}</pre>
|
||
{{if eq $i.Kind "webhook"}}<h3>Delivery</h3><p class="small">POST to <code>/api/v1/webhooks/{{$i.ID}}</code> with headers <code>X-Noema-Timestamp</code> (unix seconds) and <code>X-Noema-Signature: sha256=HMAC_SHA256(secret, timestamp + "." + body)</code>. Body: <code>{"title":"…","text":"…","reference":"…","salience":0.6}</code>. Unsigned deliveries and replays are refused.</p>{{end}}
|
||
{{if $i.State}}<h3>State</h3><pre class="json">{{pretty (jsonOf $i.State)}}</pre>{{end}}</div>
|
||
<div class="card"><h2>Recent runs</h2>{{if .Data.Runs}}<table class="table compact"><thead><tr><th>Started</th><th class="num">Items</th><th class="num">Observations</th><th class="num">Errors</th><th>Notes</th></tr></thead><tbody>{{range .Data.Runs}}<tr><td class="small muted nowrap">{{.StartedAt.Local.Format "01-02 15:04:05"}}</td><td class="num">{{.Items}}</td><td class="num">{{.Observations}}</td><td class="num {{if .Errors}}danger{{end}}">{{.Errors}}</td><td class="small">{{with .Error}}<span class="danger">{{.}}</span> {{end}}<span class="muted">{{trunc (printf "%s" .Notes) 160}}</span></td></tr>{{end}}</tbody></table>{{else}}<p class="muted">No runs yet.</p>{{end}}</div>
|
||
</section>
|
||
{{if .Data.Documents}}<div class="card"><h2>Ingested documents</h2><table class="table compact"><thead><tr><th>Status</th><th>Title</th><th>Type</th><th class="num">Bytes</th><th class="num">Chars</th><th>Reference</th><th></th></tr></thead><tbody>{{range .Data.Documents}}<tr><td><span class="badge {{if eq .Status "ingested"}}ok{{else if eq .Status "rejected"}}danger{{else}}{{end}}">{{.Status}}</span>{{with .Error}}<div class="small muted">{{.}}</div>{{end}}</td><td>{{.Title}}</td><td class="small">{{.ContentType}}</td><td class="num">{{.SizeBytes}}</td><td class="num">{{.ExtractedChars}}</td><td class="small mono">{{trunc .Reference 60}}</td><td>{{if .EventID}}<a class="small" href="/events/{{.EventID}}">event</a>{{end}}</td></tr>{{end}}</tbody></table></div>{{end}}
|
||
{{end}}
|