update
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
{{define "audit.html"}}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{.Title}} · TAPM</title>
|
||||
<link rel="stylesheet" href="/static/app.css">
|
||||
</head>
|
||||
<body>
|
||||
{{template "topbar" .}}
|
||||
|
||||
<main class="page">
|
||||
<section class="view-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Audit trail</p>
|
||||
<h1>Security events.</h1>
|
||||
<p>Review retained broker activity and narrow the results to a deployment, host, package, or technician.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<form action="/portal/audit" method="get" class="audit-filters">
|
||||
<label>Time range
|
||||
<select name="audit_range">
|
||||
<option value="24h" {{if eq .AuditFilters.TimeRange "24h"}}selected{{end}}>Past 24 hours</option>
|
||||
<option value="7d" {{if eq .AuditFilters.TimeRange "7d"}}selected{{end}}>Past 7 days</option>
|
||||
<option value="30d" {{if eq .AuditFilters.TimeRange "30d"}}selected{{end}}>Past 30 days</option>
|
||||
<option value="90d" {{if eq .AuditFilters.TimeRange "90d"}}selected{{end}}>Past 90 days</option>
|
||||
<option value="all" {{if eq .AuditFilters.TimeRange "all"}}selected{{end}}>All retained events</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Event type
|
||||
<select name="audit_event">
|
||||
<option value="">All event types</option>
|
||||
{{range .AuditEventTypes}}
|
||||
<option value="{{.}}" {{if eq $.AuditFilters.EventType .}}selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</label>
|
||||
<label>Technician / actor <input name="audit_actor" value="{{.AuditFilters.Actor}}" placeholder="taiadmin"></label>
|
||||
<label>Hostname <input name="audit_hostname" value="{{.AuditFilters.Hostname}}" placeholder="pve01"></label>
|
||||
<label>Package ID <input name="audit_package" value="{{.AuditFilters.PackageSlug}}" placeholder="sentinelone-linux"></label>
|
||||
<label>Source IP <input name="audit_ip" value="{{.AuditFilters.SourceIP}}" placeholder="10.10.1.25"></label>
|
||||
<label>Details contain <input name="audit_details" value="{{.AuditFilters.Details}}" placeholder="customer or action"></label>
|
||||
<div class="audit-filter-actions">
|
||||
<button class="button secondary" type="submit">Apply filters</button>
|
||||
<a class="text-button" href="/portal/audit?audit_range=30d">Clear filters</a>
|
||||
</div>
|
||||
<p class="form-help audit-filter-note">Audit records are retained indefinitely. Up to the newest 250 matching events are shown.</p>
|
||||
</form>
|
||||
{{template "audit-rows" .}}
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
@@ -0,0 +1,44 @@
|
||||
{{define "topbar"}}
|
||||
<header class="topbar">
|
||||
<div class="brand">
|
||||
<span class="wordmark">TAPM</span>
|
||||
<span class="product-name">Deployment Access</span>
|
||||
</div>
|
||||
<nav class="portal-nav" aria-label="Portal">
|
||||
<a href="/portal" {{if eq .CurrentView "codes"}}class="active" aria-current="page"{{end}}>Codes</a>
|
||||
<a href="/portal/packages" {{if eq .CurrentView "packages"}}class="active" aria-current="page"{{end}}>Packages</a>
|
||||
<a href="/portal/audit" {{if eq .CurrentView "audit"}}class="active" aria-current="page"{{end}}>Audit</a>
|
||||
</nav>
|
||||
<div class="operator">
|
||||
<span>{{.Technician.DisplayName}}</span>
|
||||
<form action="/auth/logout" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<button class="text-button" type="submit">Sign out</button>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
{{end}}
|
||||
|
||||
{{define "audit-rows"}}
|
||||
<div class="audit-table">
|
||||
{{range .AuditEvents}}
|
||||
<div class="audit-row">
|
||||
<div>
|
||||
<strong>{{.EventType}}</strong>
|
||||
<small>{{formatTime .CreatedAt}}</small>
|
||||
</div>
|
||||
<div>
|
||||
{{if .Actor}}<span>{{.Actor}}</span>{{end}}
|
||||
{{if .Hostname}}<span>{{.Hostname}}</span>{{end}}
|
||||
{{if .PackageSlug}}<span>{{.PackageSlug}}</span>{{end}}
|
||||
</div>
|
||||
<div>
|
||||
<span>{{.SourceIP}}</span>
|
||||
{{if .Details}}<small>{{.Details}}</small>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="empty audit-empty">No security events match this view.</p>
|
||||
{{end}}
|
||||
</div>
|
||||
{{end}}
|
||||
@@ -0,0 +1,96 @@
|
||||
{{define "packages.html"}}
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{.Title}} · TAPM</title>
|
||||
<link rel="stylesheet" href="/static/app.css">
|
||||
<script src="/static/app.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
{{template "topbar" .}}
|
||||
|
||||
<main class="page">
|
||||
{{if .Notice}}<div class="notice">{{.Notice}}</div>{{end}}
|
||||
|
||||
<section class="view-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Registry catalog</p>
|
||||
<h1>Protected packages.</h1>
|
||||
<p>Add installers or replace the current version while keeping a stable package ID.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel">
|
||||
<div class="package-layout">
|
||||
<div class="package-table">
|
||||
<p class="form-title">Current catalog</p>
|
||||
{{range .Packages}}
|
||||
<div class="package-row">
|
||||
<div>
|
||||
<strong>{{.DisplayName}}</strong>
|
||||
<small>{{.Slug}} · {{.PackageVersion}}</small>
|
||||
</div>
|
||||
<span class="status {{if .Enabled}}enabled{{end}}">{{if .Enabled}}Enabled{{else}}Disabled{{end}}</span>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="empty">No protected packages have been added.</p>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="package-forms">
|
||||
{{if .Packages}}
|
||||
<form action="/portal/packages/upload" method="post" enctype="multipart/form-data" class="stack compact" data-upload-form>
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<input type="hidden" name="mode" value="update">
|
||||
<p class="form-title">Update a package</p>
|
||||
<label>Package
|
||||
<select name="slug" required>
|
||||
{{range .Packages}}
|
||||
<option value="{{.Slug}}">{{.DisplayName}} ({{.Slug}} · {{.PackageVersion}})</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</label>
|
||||
<label>New version <input name="package_version" placeholder="26.2.0.10" required></label>
|
||||
<label class="toggle"><input type="checkbox" name="enabled" value="1" checked> Enable after upload</label>
|
||||
<label>Replacement installer <input name="package_file" type="file" required></label>
|
||||
<p class="form-help">The package ID stays the same. Existing authorizations automatically use the replacement, and its prior Gitea version is removed.</p>
|
||||
<button class="button primary" type="submit">Replace current package</button>
|
||||
<p class="upload-status" data-upload-status aria-live="polite"></p>
|
||||
</form>
|
||||
{{end}}
|
||||
|
||||
<form action="/portal/packages/upload" method="post" enctype="multipart/form-data" class="stack compact form-section" data-upload-form>
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<input type="hidden" name="mode" value="create">
|
||||
<p class="form-title">Add a protected package</p>
|
||||
<label>Package ID <input name="slug" placeholder="sentinelone-linux" pattern="[a-z0-9_-]+" required></label>
|
||||
<label>Display name <input name="display_name" placeholder="SentinelOne Linux Agent" required></label>
|
||||
<label>Version <input name="package_version" placeholder="26.2.0.10" required></label>
|
||||
<label class="toggle"><input type="checkbox" name="enabled" value="1" checked> Enable after upload</label>
|
||||
<label>Installer file <input name="package_file" type="file" required></label>
|
||||
<button class="button secondary" type="submit">Upload new package</button>
|
||||
<p class="upload-status" data-upload-status aria-live="polite"></p>
|
||||
</form>
|
||||
|
||||
<details class="manual-metadata">
|
||||
<summary>Register package metadata manually</summary>
|
||||
<form action="/portal/packages" method="post" class="stack compact">
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<label>Package ID <input name="slug" placeholder="sentinelone-linux" pattern="[a-z0-9_-]+" required></label>
|
||||
<label>Display name <input name="display_name" placeholder="SentinelOne Linux Agent" required></label>
|
||||
<label>Version <input name="package_version" placeholder="26.1.1.31" required></label>
|
||||
<label>Filename <input name="file_name" placeholder="SentinelAgent_linux_x86_64.deb" required></label>
|
||||
<label>SHA-256 <input name="sha256" minlength="64" maxlength="64" placeholder="64 hexadecimal characters" required></label>
|
||||
<label class="toggle"><input type="checkbox" name="enabled" value="1"> Enable for new authorizations</label>
|
||||
<button class="button secondary" type="submit">Save package metadata</button>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
@@ -9,19 +9,7 @@
|
||||
<script src="/static/app.js" defer></script>
|
||||
</head>
|
||||
<body>
|
||||
<header class="topbar">
|
||||
<div>
|
||||
<span class="wordmark">TAPM</span>
|
||||
<span class="product-name">Deployment Access</span>
|
||||
</div>
|
||||
<div class="operator">
|
||||
<span>{{.Technician.DisplayName}}</span>
|
||||
<form action="/auth/logout" method="post">
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<button class="text-button" type="submit">Sign out</button>
|
||||
</form>
|
||||
</div>
|
||||
</header>
|
||||
{{template "topbar" .}}
|
||||
|
||||
<main class="page">
|
||||
{{if .NewCode}}
|
||||
@@ -114,7 +102,7 @@
|
||||
{{end}}
|
||||
</fieldset>
|
||||
|
||||
<button class="button primary" type="submit">Create 3-hour code</button>
|
||||
<button class="button primary" type="submit">Create deployment code</button>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
@@ -151,144 +139,21 @@
|
||||
{{end}}
|
||||
</article>
|
||||
{{else}}
|
||||
<p class="empty">No deployment authorizations have been created.</p>
|
||||
<p class="empty authorization-empty">No deployment authorizations have been created.</p>
|
||||
{{end}}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<section class="panel package-admin">
|
||||
<div class="panel-heading">
|
||||
<div>
|
||||
<p class="eyebrow">Registry catalog</p>
|
||||
<h2>Protected packages</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="package-layout">
|
||||
<div class="package-table">
|
||||
{{range .Packages}}
|
||||
<div class="package-row">
|
||||
<div>
|
||||
<strong>{{.DisplayName}}</strong>
|
||||
<small>{{.Slug}} · {{.PackageVersion}}</small>
|
||||
</div>
|
||||
<span class="status {{if .Enabled}}enabled{{end}}">{{if .Enabled}}Enabled{{else}}Disabled{{end}}</span>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="empty">Add the first package after publishing it to Gitea.</p>
|
||||
{{end}}
|
||||
</div>
|
||||
|
||||
<div class="package-forms">
|
||||
{{if .Packages}}
|
||||
<form action="/portal/packages/upload" method="post" enctype="multipart/form-data" class="stack compact" data-upload-form>
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<input type="hidden" name="mode" value="update">
|
||||
<p class="form-title">Update a package</p>
|
||||
<label>Package
|
||||
<select name="slug" required>
|
||||
{{range .Packages}}
|
||||
<option value="{{.Slug}}">{{.DisplayName}} ({{.Slug}} · {{.PackageVersion}})</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</label>
|
||||
<label>New version <input name="package_version" placeholder="26.2.0.10" required></label>
|
||||
<label class="toggle"><input type="checkbox" name="enabled" value="1" checked> Enable after upload</label>
|
||||
<label>Replacement installer <input name="package_file" type="file" required></label>
|
||||
<p class="form-help">The package ID stays the same. Existing authorizations automatically use the replacement, and its prior Gitea version is removed.</p>
|
||||
<button class="button primary" type="submit">Replace current package</button>
|
||||
<p class="upload-status" data-upload-status aria-live="polite"></p>
|
||||
</form>
|
||||
{{end}}
|
||||
|
||||
<form action="/portal/packages/upload" method="post" enctype="multipart/form-data" class="stack compact" data-upload-form>
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<input type="hidden" name="mode" value="create">
|
||||
<p class="form-title">Add a protected package</p>
|
||||
<label>Package ID <input name="slug" placeholder="sentinelone-linux" pattern="[a-z0-9_-]+" required></label>
|
||||
<label>Display name <input name="display_name" placeholder="SentinelOne Linux Agent" required></label>
|
||||
<label>Version <input name="package_version" placeholder="26.2.0.10" required></label>
|
||||
<label class="toggle"><input type="checkbox" name="enabled" value="1" checked> Enable after upload</label>
|
||||
<label>Installer file <input name="package_file" type="file" required></label>
|
||||
<button class="button secondary" type="submit">Upload new package</button>
|
||||
<p class="upload-status" data-upload-status aria-live="polite"></p>
|
||||
</form>
|
||||
|
||||
<details class="manual-metadata">
|
||||
<summary>Register package metadata manually</summary>
|
||||
<form action="/portal/packages" method="post" class="stack compact">
|
||||
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
|
||||
<label>Package ID <input name="slug" placeholder="sentinelone-linux" pattern="[a-z0-9_-]+" required></label>
|
||||
<label>Display name <input name="display_name" placeholder="SentinelOne Linux Agent" required></label>
|
||||
<label>Version <input name="package_version" placeholder="26.1.1.31" required></label>
|
||||
<label>Filename <input name="file_name" placeholder="SentinelAgent_linux_x86_64.deb" required></label>
|
||||
<label>SHA-256 <input name="sha256" minlength="64" maxlength="64" placeholder="64 hexadecimal characters" required></label>
|
||||
<label class="toggle"><input type="checkbox" name="enabled" value="1"> Enable for new authorizations</label>
|
||||
<button class="button secondary" type="submit">Save package metadata</button>
|
||||
</form>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel audit-panel">
|
||||
<div class="panel-heading">
|
||||
<div class="panel-heading panel-heading-action">
|
||||
<div>
|
||||
<p class="eyebrow">Audit trail</p>
|
||||
<h2>Security events</h2>
|
||||
<p class="eyebrow">Audit preview</p>
|
||||
<h2>Latest 15 security events</h2>
|
||||
</div>
|
||||
<a class="button secondary" href="/portal/audit">Review full audit trail</a>
|
||||
</div>
|
||||
<form action="/portal" method="get" class="audit-filters">
|
||||
<label>Time range
|
||||
<select name="audit_range">
|
||||
<option value="24h" {{if eq .AuditFilters.TimeRange "24h"}}selected{{end}}>Past 24 hours</option>
|
||||
<option value="7d" {{if eq .AuditFilters.TimeRange "7d"}}selected{{end}}>Past 7 days</option>
|
||||
<option value="30d" {{if eq .AuditFilters.TimeRange "30d"}}selected{{end}}>Past 30 days</option>
|
||||
<option value="90d" {{if eq .AuditFilters.TimeRange "90d"}}selected{{end}}>Past 90 days</option>
|
||||
<option value="all" {{if eq .AuditFilters.TimeRange "all"}}selected{{end}}>All retained events</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>Event type
|
||||
<select name="audit_event">
|
||||
<option value="">All event types</option>
|
||||
{{range .AuditEventTypes}}
|
||||
<option value="{{.}}" {{if eq $.AuditFilters.EventType .}}selected{{end}}>{{.}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
</label>
|
||||
<label>Technician / actor <input name="audit_actor" value="{{.AuditFilters.Actor}}" placeholder="taiadmin"></label>
|
||||
<label>Hostname <input name="audit_hostname" value="{{.AuditFilters.Hostname}}" placeholder="pve01"></label>
|
||||
<label>Package ID <input name="audit_package" value="{{.AuditFilters.PackageSlug}}" placeholder="sentinelone-linux"></label>
|
||||
<label>Source IP <input name="audit_ip" value="{{.AuditFilters.SourceIP}}" placeholder="10.10.1.25"></label>
|
||||
<label>Details contain <input name="audit_details" value="{{.AuditFilters.Details}}" placeholder="customer or action"></label>
|
||||
<div class="audit-filter-actions">
|
||||
<button class="button secondary" type="submit">Apply filters</button>
|
||||
<a class="text-button" href="/portal?audit_range=30d">Clear filters</a>
|
||||
</div>
|
||||
<p class="form-help audit-filter-note">Audit records are retained indefinitely. Up to the newest 250 matching events are shown.</p>
|
||||
</form>
|
||||
<div class="audit-table">
|
||||
{{range .AuditEvents}}
|
||||
<div class="audit-row">
|
||||
<div>
|
||||
<strong>{{.EventType}}</strong>
|
||||
<small>{{formatTime .CreatedAt}}</small>
|
||||
</div>
|
||||
<div>
|
||||
{{if .Actor}}<span>{{.Actor}}</span>{{end}}
|
||||
{{if .Hostname}}<span>{{.Hostname}}</span>{{end}}
|
||||
{{if .PackageSlug}}<span>{{.PackageSlug}}</span>{{end}}
|
||||
</div>
|
||||
<div>
|
||||
<span>{{.SourceIP}}</span>
|
||||
{{if .Details}}<small>{{.Details}}</small>{{end}}
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="empty audit-empty">No security events match these filters.</p>
|
||||
{{end}}
|
||||
</div>
|
||||
{{template "audit-rows" .}}
|
||||
</section>
|
||||
</main>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user