docs consolidation

This commit is contained in:
master
2026-01-07 10:23:21 +02:00
parent 4789027317
commit 044cf0923c
515 changed files with 5460 additions and 5292 deletions

View File

@@ -0,0 +1,101 @@
# Policy Templates — YAML & Rego Examples
StellaOps lets you enforce *pass / fail* rules in two ways:
1. **YAML “quick policies”** — simple equality / inequality checks.
2. **OPA Rego modules** — fullpower logic for complex organisations.
> **Precedence:** If the same image is subject to both a YAML rule *and* a Rego
> module, the **Rego result wins**. That is, `deny` in Rego overrides any
> `allow` in YAML.
---
## 1·YAML quick policy
```yaml
# file: policies/root_user.yaml
version: 1
id: root-user
description: Disallow images that run as root
severity: high
rules:
- field: ".config.user"
operator: "equals"
value: "root"
deny_message: "Image runs as root — block."
````
Place the file under `/opt/stella/plugins/policies/`.
---
## 2·Rego example (deny on critical CVE)
```rego
# file: policies/deny_critical.rego
package stella.policy
default deny = []
deny[msg] {
some f
input.findings[f].severity == "critical"
msg := sprintf("Critical CVE %s build blocked", [input.findings[f].id])
}
```
*Input schema* — the Rego `input` document matches the public
`ScanResult` POCO (see SDK). Use the bundled JSON schema in
`share/schemas/scanresult.schema.json` for IDE autocompletion.
---
## 3·Passthrough warnings (Rego)
Return a `warn` array to surface nonblocking messages in the UI:
```rego
package stella.policy
warn[msg] {
input.image.base == "ubuntu:16.04"
msg := "Image uses EOL Ubuntu 16.04 — please upgrade."
}
```
Warnings decrement the **quality score** but do *not* affect the CLI exit
code.
---
## 4·Testing policies locally
```bash
# run policy evaluation without pushing to DB
stella scan alpine:3.20 --policy-only \
--policies ./policies/
```
The CLI prints `PASS`, `WARN` or `DENY` plus structured JSON.
Unittest your Rego modules with the OPA binary:
```bash
opa test policies/
```
---
## 5·Developer quickstart (plugins)
Need logic beyond Rego? Implement a plugin via **C#/.NET {{ dotnet }}** and
the `StellaOps.SDK` NuGet:
* Tutorial: [`dev/PLUGIN_DEV_GUIDE.md`](dev/PLUGIN_DEV_GUIDE.md)
* Quick reference: `/plugins/`
---
*Last updated {{ "now" | date: "%Y%m%d" }} — constants autoinjected.*

View File

@@ -16,7 +16,7 @@ This contract defines the integration between the Signals service (reachability
The canonical JSON schema is at:
```
docs/schemas/reachability-input.schema.json
docs/modules/policy/schemas/reachability-input.schema.json
```
## 3. Data Flow

View File

@@ -0,0 +1,93 @@
# QuotaEnforcement — Flow Diagram (rev2.1)
> **Scope** this document explains *how* the freetier limits are enforced
> inside the scanner service. For policy rationale and legal aspects, see
> [`29_LEGAL_FAQ_QUOTA.md`](29_LEGAL_FAQ_QUOTA.md).
---
## 0·Key parameters (rev2.1)
| Symbol | Value | Meaning |
|--------|-------|---------|
| `L_anon` | **{{ quota_anon }}** | Daily ceiling for anonymous users |
| `L_jwt` | **{{ quota_token }}** | Daily ceiling for token holders |
| `T_warn` | `200` | Soft reminder threshold |
| `D_soft` | `5000ms` | Delay for *first 30* overquota scans |
| `D_hard` | `60000ms` | Delay for all scans beyond the soft window |
`L_active` is `L_jwt` if a valid token is present; else `L_anon`.
---
## 1·Sequence diagram
```mermaid
sequenceDiagram
participant C as Client
participant API as Scanner API
participant VALKEY as Valkey (quota)
C->>API: /scan
API->>VALKEY: INCR quota:<key>
VALKEY-->>API: new_count
alt new_count ≤ L_active
API-->>C: 202 Accepted (no delay)
else new_count ≤ L_active + 30
API->>C: wait D_soft
API-->>C: 202 Accepted
else
API->>C: wait D_hard
API-->>C: 202 Accepted
end
````
*Counters autoexpire **24h** after first increment (00:00UTC reset).*
---
## 2·Valkey key layout
| Key pattern | TTL | Description |
| ---------------------- | ---- | --------------------------------- |
| `quota:ip:<sha256>` | 24h | Anonymous quota per *hashed* IP |
| `quota:tid:<sha256>` | 24h | Token quota per *hashed* tokenID |
| `quota:ip:<sha256>:ts` | 24h | Firstseen timestamp (ISO8601) |
Keys share a common TTL for efficient mass expiry via `valkey-cli --scan`.
---
## 3·Pseudocode (Gostyle)
```go
func gate(key string, limit int) (delay time.Duration) {
cnt, _ := rdb.Incr(ctx, key).Result()
switch {
case cnt <= limit:
return 0 // under quota
case cnt <= limit+30:
return 5 * time.Second
default:
return 60 * time.Second
}
}
```
*The middleware applies `time.Sleep(delay)` **before** processing the scan
request; it never returns `HTTP429` under the free tier.*
---
## 4·Metrics & monitoring
| Metric | PromQL sample | Alert |
| ------------------------------ | ------------------------------------------ | --------------------- |
| `stella_quota_soft_hits_total` | `increase(...[5m]) > 50` | Many users near limit |
| `stella_quota_hard_hits_total` | `rate(...[1h]) > 0.1` | Potential abuse |
| Average delay per request | `histogram_quantile(0.95, sum(rate(...)))` | P95 < 1s expected |
---
*Generated {{ "now" | date: "%Y%m%d" }} — values pulled from central constants.*

View File

@@ -0,0 +1,120 @@
# FreeTier Quota — **{{ quota_anon }}/{{ quota_token }} Scans per UTC Day**
StellaOps is free for individual developers and small teams.
To avoid registry abuse the scanner enforces a **twotier daily quota**
— fully offline capable.
| Mode | Daily ceiling | How to obtain |
|------|---------------|---------------|
| **Anonymous** | **{{ quota_anon }} scans** | No registration. Works online or airgapped. |
| **Free JWT token** | **{{ quota_token }} scans** | Email `token@stella-ops.org` (blank body). Bot replies with a signed JWT. |
*Soft reminder banner appears at 200 scans. Exceeding the limit never blocks
the CLI/UI introduce a delay, detailed below.*
---
## 1·Token structure
```jsonc
{
"iss": "stella-ops.org",
"sub": "free-tier",
"tid": "7d2285…", // 32byte random tokenID
"tier": {{ quota_token }}, // daily scans allowed
"exp": 1767139199 // POSIX seconds (mandatory) token expiry
}
````
* The **tokenID (`tid`)** not the email is hashed *(SHA256 + salt)*
and stored for counter lookup.
* Verification uses the bundled public key (`keys/cosign.pub`) so **offline
hosts validate tokens locally**. An optional `exp` claim may be present;
if absent, the default is a farfuture timestamp used solely for schema
compatibility.
---
## 2·Enforcement algorithm (rev 2.1)
| Step | Operation | Typical latency |
| ---- | ------------------------------------------------------------------------------ | ------------------------------------ |
| 1 | `key = sha256(ip)` *or* `sha256(tid)` | <0.1ms |
| 2 | `count = INCR quota:<key>` in Valkey (24h TTL) | 0.2ms (Lua) |
| 3 | If `count > limit` `WAIT delay_ms` | first 30×5000ms then 60000ms |
| 4 | Return HTTP429 **only if** `delay > 60s` (should never fire under free tier) | |
*Counters reset at **00:00UTC**.*
---
## 3·CLI / API integration
```bash
# Example .env
docker run --rm \
-e DOCKER_HOST="$DOCKER_HOST" \ # remotedaemon pointer
-v "$WORKSPACE/${SBOM_FILE}:/${SBOM_FILE}:ro" \ # mount SBOM under same name at container root
-e STELLA_OPS_URL="https://${STELLA_URL}" \ # where the CLI posts findings
"$STELLA_URL/registry/stella-cli:latest" \
scan --sbom "/${SBOM_FILE}" "$IMAGE"
```
*No JWT? → scanner defaults to anonymous quota.*
---
## 4·Data retention & privacy
| Data | Retention | Purpose |
| ---------------------- | ------------------------------------ | ---------------- |
| IP hash (`quota:ip:*`) | 7days, then salted hash only | Abuse ratelimit |
| TokenID hash | Until revoked | Counter lookup |
| Email (token request) | ≤7days unless newsletters optedin | Deliver the JWT |
*No personal data leaves your infrastructure when running offline.*
---
## 5·Common questions
<details>
<summary>What happens at exactly 200 scans?</summary>
> The UI/CLI shows a yellow “fairuse reminder”.
> No throttling is applied yet.
> Once you cross the full limit, the **first 30** overquota scans incur a
> 5second delay; further excess scans delay **60s** each.
</details>
<details>
<summary>Does the quota differ offline?</summary>
> No. Counters are evaluated locally in Valkey; the same limits apply even
> without Internet access.
</details>
<details>
<summary>Can I reset counters manually?</summary>
> Yes delete the `quota:*` keys in Valkey, but we recommend letting them
> expire at midnight to keep statistics meaningful.
</details>
---
## 6·Revision history
| Version | Date | Notes |
| ------- | ---------- | ------------------------------------------------------------------- |
| **2.1** | 20250716 | Consolidated into single source; delays retuned (30×5s60s). |
|  2.0 | 20250407 | Switched from MongoDB (removed Sprint 4400) to Valkey (Redis-compatible) for quota counters. |
|  1.0 | 20241220 | Initial freetier design. |
---
**Authoritative source** — any doc or website section that references quotas
*must* link to this file instead of duplicating text.

View File

@@ -2,7 +2,7 @@
> **Status:** Implementation in Progress (SPRINT_3000_0100_0001)
> **Predicate URI:** `https://stellaops.dev/predicates/policy-verdict@v1`
> **Schema:** [`docs/schemas/stellaops-policy-verdict.v1.schema.json`](../schemas/stellaops-policy-verdict.v1.schema.json)
> **Schema:** [`docs/modules/policy/schemas/stellaops-policy-verdict.v1.schema.json`](../schemas/stellaops-policy-verdict.v1.schema.json)
---