Files
shopdb-flask/plugins/printers/models/supply_alert.py
cproudlock 75386d2f51 geenforce: resource-scope binding for fetch tokens (0.15.0)
A geenforce.fetch token can now be pinned to specific manifest scopes so a
fleet-wide key (a display's, delivered by DSC or baked into the image) is not a
skeleton key for the whole content store. NULL binding = unrestricted, so every
existing service token keeps working.

Core:
- ApiToken.resourcescopes column + resourcescopelist property (migration
  7d30_apitoken_resourcescopes; NULL = unrestricted).
- apitokens API create/update accept + persist an optional resourcescopes list
  (a resource-name allowlist; not permission-catalog names).
- New contract helper authorized_service_token(scope): same check as
  service_token_authorized but returns the ApiToken so a plugin can read its
  binding. Contract 0.14.0 -> 0.15.0; also export SupportTeam.

GE-Enforce enforcement:
- get_manifest: a bound token requesting a scope outside its allowlist -> 403.
- get_payload: a bound token may only pull a blob its own scope(s) reference
  (service.blob_referenced_by_scopes); anything else -> 404 (no hash probing).
- Decorator stashes the authorized token on g for the route to read.

Also fixes a pre-existing contract-surface violation: the printers/printedparts
alert helpers imported shopdb.core.models / shopdb.extensions directly; now
via shopdb.api (SupportTeam newly exported). Docs: GE-ENFORCE-DISPLAY.md
provisioning note, PLUGIN-HOOKS.md, CLAUDE.md.

9 new resource-binding tests; full suite 1131 passing.
2026-07-23 09:02:42 -04:00

41 lines
1.3 KiB
Python

"""Per-printer supply alert state.
The supply poller (flask printers check-toner-alerts) is stateless: it reads
live levels from Zabbix each run. To alert once per downward crossing (and
re-arm after a refill) it needs to remember the last tier it alerted for each
printer + supply. One row per (printerid, supplykey); supplykey is the toner
color (black/cyan/magenta/yellow) or the raw item name when color is unknown.
"""
from shopdb.api import db, BaseModel
class PrinterSupplyAlert(BaseModel):
"""Last-alerted tier for one printer supply. lasttier in ok/warning/critical."""
__tablename__ = 'printersupplyalerts'
printersupplyalertid = db.Column(db.Integer, primary_key=True)
printerid = db.Column(
db.Integer,
db.ForeignKey('printers.printerid', ondelete='CASCADE'),
nullable=False,
index=True,
)
supplykey = db.Column(
db.String(64),
nullable=False,
comment='Toner color, or Zabbix item name when color is unknown',
)
lasttier = db.Column(
db.String(16),
nullable=False,
default='ok',
comment='Last tier alerted: ok, warning, or critical',
)
__table_args__ = (
db.UniqueConstraint('printerid', 'supplykey',
name='uq_printersupplyalert_printer_key'),
)