capacium-models 0.5.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- capacium_models-0.5.0/LICENSE +21 -0
- capacium_models-0.5.0/PKG-INFO +99 -0
- capacium_models-0.5.0/README.md +73 -0
- capacium_models-0.5.0/pyproject.toml +43 -0
- capacium_models-0.5.0/setup.cfg +4 -0
- capacium_models-0.5.0/src/capacium_models/__init__.py +66 -0
- capacium_models-0.5.0/src/capacium_models/keys.py +123 -0
- capacium_models-0.5.0/src/capacium_models/labels.py +75 -0
- capacium_models-0.5.0/src/capacium_models/models.py +389 -0
- capacium_models-0.5.0/src/capacium_models/search.py +141 -0
- capacium_models-0.5.0/src/capacium_models/trust.py +211 -0
- capacium_models-0.5.0/src/capacium_models.egg-info/PKG-INFO +99 -0
- capacium_models-0.5.0/src/capacium_models.egg-info/SOURCES.txt +18 -0
- capacium_models-0.5.0/src/capacium_models.egg-info/dependency_links.txt +1 -0
- capacium_models-0.5.0/src/capacium_models.egg-info/requires.txt +3 -0
- capacium_models-0.5.0/src/capacium_models.egg-info/top_level.txt +1 -0
- capacium_models-0.5.0/tests/test_keys.py +119 -0
- capacium_models-0.5.0/tests/test_labels.py +117 -0
- capacium_models-0.5.0/tests/test_models.py +507 -0
- capacium_models-0.5.0/tests/test_search.py +137 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Capacium
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: capacium-models
|
|
3
|
+
Version: 0.5.0
|
|
4
|
+
Summary: Shared domain models for the Capacium ecosystem — Listing, TrustState, TrustMachine, and more
|
|
5
|
+
Author: Capacium
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Capacium/capacium-models
|
|
8
|
+
Project-URL: Repository, https://github.com/Capacium/capacium-models
|
|
9
|
+
Project-URL: Issues, https://github.com/Capacium/capacium-models/issues
|
|
10
|
+
Keywords: capacium,models,listing,trust,ai-agents
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Provides-Extra: dev
|
|
24
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
25
|
+
Dynamic: license-file
|
|
26
|
+
|
|
27
|
+
# capacium-models
|
|
28
|
+
|
|
29
|
+
> [!NOTE]
|
|
30
|
+
> **Public mirror.** The canonical repository is hosted on our self-hosted git.
|
|
31
|
+
> This GitHub copy is a read-only mirror kept in sync for visibility and
|
|
32
|
+
> installation. Bug reports are welcome via Issues; pull requests are applied
|
|
33
|
+
> upstream and synced back here.
|
|
34
|
+
|
|
35
|
+
Shared domain models for the Capacium ecosystem. Used by `capacium-exchange` and `capacium-crawler`.
|
|
36
|
+
|
|
37
|
+
## Installation
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install capacium-models
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Models
|
|
44
|
+
|
|
45
|
+
| Model | Description |
|
|
46
|
+
|-------|-------------|
|
|
47
|
+
| `TrustState` | Enum: DISCOVERED → PENDING_REVIEW → VERIFIED → SIGNED → DEPRECATED |
|
|
48
|
+
| `TrustMachine` | State machine with VALID_TRANSITIONS, can_transition(), transition() |
|
|
49
|
+
| `Listing` | Full listing model (24 fields, auto-UUID, auto-timestamps) |
|
|
50
|
+
| `Publisher` | Publisher profile with verification support |
|
|
51
|
+
| `MCPClient` | Enum of supported MCP clients |
|
|
52
|
+
| `MCPMetadata` | MCP-specific metadata (transport, runtime, auth_model, etc.) |
|
|
53
|
+
| `Category` / `Subcategory` / `TagCount` | Taxonomy models |
|
|
54
|
+
| `Collection` | Curated collection of listing IDs |
|
|
55
|
+
| `ClaimRequest` / `VerificationRecord` | Trust workflow models |
|
|
56
|
+
| `SearchQuery` | Faceted search query model (16 fields) |
|
|
57
|
+
| `ExchangeSearch` | Faceted search SQL engine |
|
|
58
|
+
|
|
59
|
+
The package-level `TRUST_BADGES` and `get_trust_badge()` exports retain the
|
|
60
|
+
rich badge metadata introduced in v0.4.0. UI-facing canonical text labels,
|
|
61
|
+
including the string-only trust labels, live in `capacium_models.labels`.
|
|
62
|
+
|
|
63
|
+
## Usage
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from capacium_models import Listing, TrustState, TrustMachine
|
|
67
|
+
|
|
68
|
+
# Create a discovered listing
|
|
69
|
+
listing = Listing(
|
|
70
|
+
canonical_name="org/my-mcp-server",
|
|
71
|
+
package_type="mcp-server",
|
|
72
|
+
canonical_source_url="https://github.com/org/my-mcp-server",
|
|
73
|
+
short_description="A cool MCP server",
|
|
74
|
+
trust_state=TrustState.DISCOVERED,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Transition through trust states
|
|
78
|
+
machine = TrustMachine()
|
|
79
|
+
if machine.can_transition(listing.trust_state, TrustState.PENDING_REVIEW):
|
|
80
|
+
listing = machine.transition(
|
|
81
|
+
listing,
|
|
82
|
+
TrustState.PENDING_REVIEW,
|
|
83
|
+
"Validated metadata",
|
|
84
|
+
)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Dependencies
|
|
88
|
+
|
|
89
|
+
Zero runtime dependencies — stdlib only (`dataclasses`, `enum`, `uuid`, `datetime`, `json`, `typing`).
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
MIT
|
|
94
|
+
|
|
95
|
+
## Development
|
|
96
|
+
|
|
97
|
+
Canonical repository: **self-hosted Forgejo** — `git.langevc.com/capacium/capacium-models`
|
|
98
|
+
(`git clone git@git.langevc.com:capacium/capacium-models.git`). Develop against the Forgejo
|
|
99
|
+
clone and open pull requests there. The GitHub copy is a read-only mirror.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# capacium-models
|
|
2
|
+
|
|
3
|
+
> [!NOTE]
|
|
4
|
+
> **Public mirror.** The canonical repository is hosted on our self-hosted git.
|
|
5
|
+
> This GitHub copy is a read-only mirror kept in sync for visibility and
|
|
6
|
+
> installation. Bug reports are welcome via Issues; pull requests are applied
|
|
7
|
+
> upstream and synced back here.
|
|
8
|
+
|
|
9
|
+
Shared domain models for the Capacium ecosystem. Used by `capacium-exchange` and `capacium-crawler`.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install capacium-models
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Models
|
|
18
|
+
|
|
19
|
+
| Model | Description |
|
|
20
|
+
|-------|-------------|
|
|
21
|
+
| `TrustState` | Enum: DISCOVERED → PENDING_REVIEW → VERIFIED → SIGNED → DEPRECATED |
|
|
22
|
+
| `TrustMachine` | State machine with VALID_TRANSITIONS, can_transition(), transition() |
|
|
23
|
+
| `Listing` | Full listing model (24 fields, auto-UUID, auto-timestamps) |
|
|
24
|
+
| `Publisher` | Publisher profile with verification support |
|
|
25
|
+
| `MCPClient` | Enum of supported MCP clients |
|
|
26
|
+
| `MCPMetadata` | MCP-specific metadata (transport, runtime, auth_model, etc.) |
|
|
27
|
+
| `Category` / `Subcategory` / `TagCount` | Taxonomy models |
|
|
28
|
+
| `Collection` | Curated collection of listing IDs |
|
|
29
|
+
| `ClaimRequest` / `VerificationRecord` | Trust workflow models |
|
|
30
|
+
| `SearchQuery` | Faceted search query model (16 fields) |
|
|
31
|
+
| `ExchangeSearch` | Faceted search SQL engine |
|
|
32
|
+
|
|
33
|
+
The package-level `TRUST_BADGES` and `get_trust_badge()` exports retain the
|
|
34
|
+
rich badge metadata introduced in v0.4.0. UI-facing canonical text labels,
|
|
35
|
+
including the string-only trust labels, live in `capacium_models.labels`.
|
|
36
|
+
|
|
37
|
+
## Usage
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
from capacium_models import Listing, TrustState, TrustMachine
|
|
41
|
+
|
|
42
|
+
# Create a discovered listing
|
|
43
|
+
listing = Listing(
|
|
44
|
+
canonical_name="org/my-mcp-server",
|
|
45
|
+
package_type="mcp-server",
|
|
46
|
+
canonical_source_url="https://github.com/org/my-mcp-server",
|
|
47
|
+
short_description="A cool MCP server",
|
|
48
|
+
trust_state=TrustState.DISCOVERED,
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
# Transition through trust states
|
|
52
|
+
machine = TrustMachine()
|
|
53
|
+
if machine.can_transition(listing.trust_state, TrustState.PENDING_REVIEW):
|
|
54
|
+
listing = machine.transition(
|
|
55
|
+
listing,
|
|
56
|
+
TrustState.PENDING_REVIEW,
|
|
57
|
+
"Validated metadata",
|
|
58
|
+
)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Dependencies
|
|
62
|
+
|
|
63
|
+
Zero runtime dependencies — stdlib only (`dataclasses`, `enum`, `uuid`, `datetime`, `json`, `typing`).
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT
|
|
68
|
+
|
|
69
|
+
## Development
|
|
70
|
+
|
|
71
|
+
Canonical repository: **self-hosted Forgejo** — `git.langevc.com/capacium/capacium-models`
|
|
72
|
+
(`git clone git@git.langevc.com:capacium/capacium-models.git`). Develop against the Forgejo
|
|
73
|
+
clone and open pull requests there. The GitHub copy is a read-only mirror.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "capacium-models"
|
|
7
|
+
version = "0.5.0"
|
|
8
|
+
description = "Shared domain models for the Capacium ecosystem — Listing, TrustState, TrustMachine, and more"
|
|
9
|
+
authors = [{name = "Capacium"}]
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = []
|
|
12
|
+
license = "MIT"
|
|
13
|
+
readme = "README.md"
|
|
14
|
+
keywords = ["capacium", "models", "listing", "trust", "ai-agents"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 3 - Alpha",
|
|
17
|
+
"Intended Audience :: Developers",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Programming Language :: Python :: 3.13",
|
|
23
|
+
"Programming Language :: Python :: 3.14",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
[project.urls]
|
|
28
|
+
Homepage = "https://github.com/Capacium/capacium-models"
|
|
29
|
+
Repository = "https://github.com/Capacium/capacium-models"
|
|
30
|
+
Issues = "https://github.com/Capacium/capacium-models/issues"
|
|
31
|
+
|
|
32
|
+
[project.optional-dependencies]
|
|
33
|
+
dev = ["pytest>=7.0"]
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.package-dir]
|
|
36
|
+
"" = "src"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools.packages.find]
|
|
39
|
+
where = ["src"]
|
|
40
|
+
|
|
41
|
+
[tool.pytest.ini_options]
|
|
42
|
+
testpaths = ["tests"]
|
|
43
|
+
python_files = ["test_*.py"]
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""Shared domain models for the Capacium ecosystem.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
from capacium_models import Listing, TrustState, TrustMachine
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .models import (
|
|
8
|
+
MCPClient,
|
|
9
|
+
MCPMetadata,
|
|
10
|
+
TrustTransition,
|
|
11
|
+
Listing,
|
|
12
|
+
Publisher,
|
|
13
|
+
Category,
|
|
14
|
+
Subcategory,
|
|
15
|
+
TagCount,
|
|
16
|
+
Collection,
|
|
17
|
+
ClaimRequest,
|
|
18
|
+
VerificationRecord,
|
|
19
|
+
SearchQuery,
|
|
20
|
+
)
|
|
21
|
+
from .trust import TrustState, TrustMachine, TRUST_BADGES, get_trust_badge
|
|
22
|
+
from .keys import (
|
|
23
|
+
LICENSE_PUBLIC_KEYS,
|
|
24
|
+
UnknownLicenseKid,
|
|
25
|
+
get_license_public_key,
|
|
26
|
+
known_kids,
|
|
27
|
+
)
|
|
28
|
+
from .labels import (
|
|
29
|
+
RESOURCE_KIND_LABELS,
|
|
30
|
+
OPERATOR_TYPE_LABELS,
|
|
31
|
+
INSTALL_STATUS_LABELS,
|
|
32
|
+
get_kind_label,
|
|
33
|
+
get_operator_type_label,
|
|
34
|
+
get_install_status_label,
|
|
35
|
+
)
|
|
36
|
+
from .search import ExchangeSearch
|
|
37
|
+
|
|
38
|
+
__all__ = [
|
|
39
|
+
"MCPClient",
|
|
40
|
+
"MCPMetadata",
|
|
41
|
+
"TrustState",
|
|
42
|
+
"TrustTransition",
|
|
43
|
+
"TrustMachine",
|
|
44
|
+
"Listing",
|
|
45
|
+
"Publisher",
|
|
46
|
+
"Category",
|
|
47
|
+
"Subcategory",
|
|
48
|
+
"TagCount",
|
|
49
|
+
"Collection",
|
|
50
|
+
"ClaimRequest",
|
|
51
|
+
"VerificationRecord",
|
|
52
|
+
"SearchQuery",
|
|
53
|
+
"ExchangeSearch",
|
|
54
|
+
"TRUST_BADGES",
|
|
55
|
+
"get_trust_badge",
|
|
56
|
+
"RESOURCE_KIND_LABELS",
|
|
57
|
+
"OPERATOR_TYPE_LABELS",
|
|
58
|
+
"INSTALL_STATUS_LABELS",
|
|
59
|
+
"get_kind_label",
|
|
60
|
+
"get_operator_type_label",
|
|
61
|
+
"get_install_status_label",
|
|
62
|
+
"LICENSE_PUBLIC_KEYS",
|
|
63
|
+
"UnknownLicenseKid",
|
|
64
|
+
"get_license_public_key",
|
|
65
|
+
"known_kids",
|
|
66
|
+
]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"""License public-key registry for capacium-models consumers.
|
|
2
|
+
|
|
3
|
+
Consumers verify license tokens (issued by capacium-exchange `LicenseService`)
|
|
4
|
+
using Ed25519. The matching PRIVATE key lives ONLY in envctl on prod, under:
|
|
5
|
+
|
|
6
|
+
envctl get capacium-exchange CAPACIUM_LICENSE_SIGNING_KEY # 64-hex private
|
|
7
|
+
envctl get capacium-exchange CAPACIUM_LICENSE_SIGNING_KID # current kid
|
|
8
|
+
|
|
9
|
+
This module holds the corresponding PUBLIC keys, indexed by `kid` (key
|
|
10
|
+
identifier as embedded in license token payloads). Consumers use these to
|
|
11
|
+
verify signatures locally without round-tripping to the Exchange.
|
|
12
|
+
|
|
13
|
+
Key rotation lifecycle for a given kid:
|
|
14
|
+
- Active: issues new tokens; PRIVATE held in envctl
|
|
15
|
+
- Retired: no longer issues NEW tokens; OLD tokens still validate
|
|
16
|
+
(entry stays in this registry until last token expires)
|
|
17
|
+
- Removed: entry deleted from registry; OLD tokens fail validation
|
|
18
|
+
|
|
19
|
+
To add a new kid: append to LICENSE_PUBLIC_KEYS, bump the package version
|
|
20
|
+
(minor bump — additive); ship as a new capacium-models release. NEVER
|
|
21
|
+
remove an entry whose tokens may still be in circulation.
|
|
22
|
+
|
|
23
|
+
DECISION-001 reference: license-signing keypair is DISTINCT from
|
|
24
|
+
capability-signing keypair. kid namespace MUST start with `lic-`.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
from typing import Dict, List
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ── License public-key registry ───────────────────────────────────────────
|
|
33
|
+
#
|
|
34
|
+
# Format: dict[kid -> 64-char lowercase hex] (32 bytes Ed25519 public key)
|
|
35
|
+
#
|
|
36
|
+
# Each entry MUST match the private key currently set as
|
|
37
|
+
# CAPACIUM_LICENSE_SIGNING_KEY in envctl on capacium-prod, under the
|
|
38
|
+
# matching kid CAPACIUM_LICENSE_SIGNING_KID.
|
|
39
|
+
|
|
40
|
+
LICENSE_PUBLIC_KEYS: Dict[str, str] = {
|
|
41
|
+
# ──────────────────────────────────────────────────────────────────────
|
|
42
|
+
# kid: lic-2026-q2-01
|
|
43
|
+
# Added: 2026-06-03 (initial v2 launch — corresponds to the FIRST
|
|
44
|
+
# Ed25519 keypair generated on maintainer workstation, private uploaded
|
|
45
|
+
# to envctl on capacium-prod)
|
|
46
|
+
# ──────────────────────────────────────────────────────────────────────
|
|
47
|
+
"lic-2026-q2-01": "8e5e33e1ab3676d239a1f89cded6afca9aca0e8ba24c3b4b50ad4b71ef84e978",
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
# ── Public API ────────────────────────────────────────────────────────────
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class UnknownLicenseKid(KeyError):
|
|
55
|
+
"""Raised when a license token's `kid` is not in the public-key registry.
|
|
56
|
+
|
|
57
|
+
Consumers MUST reject the token in this case (treat as invalid signature).
|
|
58
|
+
Receiving this exception is the signal to upgrade `capacium-models` to a
|
|
59
|
+
newer version that includes the missing kid.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def get_license_public_key(kid: str) -> str:
|
|
64
|
+
"""Return the 64-char hex public key for a license kid.
|
|
65
|
+
|
|
66
|
+
Args:
|
|
67
|
+
kid: Key identifier as embedded in license token payload.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
64-char lowercase hex string representing the Ed25519 public key.
|
|
71
|
+
|
|
72
|
+
Raises:
|
|
73
|
+
UnknownLicenseKid: when `kid` is not in `LICENSE_PUBLIC_KEYS`, OR
|
|
74
|
+
when its registered value is not a valid 64-char hex string
|
|
75
|
+
(e.g., still a placeholder, malformed registry entry).
|
|
76
|
+
Consumer code MUST reject the token in this case.
|
|
77
|
+
"""
|
|
78
|
+
try:
|
|
79
|
+
pubkey = LICENSE_PUBLIC_KEYS[kid]
|
|
80
|
+
except KeyError as e:
|
|
81
|
+
raise UnknownLicenseKid(
|
|
82
|
+
f"kid={kid!r} not in LICENSE_PUBLIC_KEYS. "
|
|
83
|
+
f"Known kids: {known_kids()}. "
|
|
84
|
+
f"Upgrade capacium-models to support newer kids."
|
|
85
|
+
) from e
|
|
86
|
+
_validate_hex(kid, pubkey)
|
|
87
|
+
return pubkey
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def known_kids() -> List[str]:
|
|
91
|
+
"""Return all registered kids, sorted newest-first (lexicographic reverse).
|
|
92
|
+
|
|
93
|
+
Naming convention `lic-YYYY-qN-NN` makes lex reverse equal to
|
|
94
|
+
chronological reverse.
|
|
95
|
+
"""
|
|
96
|
+
return sorted(LICENSE_PUBLIC_KEYS.keys(), reverse=True)
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# ── Internal helpers ──────────────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def _validate_hex(kid: str, pubkey: str) -> None:
|
|
103
|
+
"""Validate that `pubkey` is a 64-char lowercase hex string.
|
|
104
|
+
|
|
105
|
+
Raises UnknownLicenseKid (not ValueError) so consumers handling kid
|
|
106
|
+
lookup errors have a single exception type to catch.
|
|
107
|
+
"""
|
|
108
|
+
if not isinstance(pubkey, str):
|
|
109
|
+
raise UnknownLicenseKid(
|
|
110
|
+
f"kid={kid!r} has non-string pubkey of type {type(pubkey).__name__}"
|
|
111
|
+
)
|
|
112
|
+
if len(pubkey) != 64:
|
|
113
|
+
raise UnknownLicenseKid(
|
|
114
|
+
f"kid={kid!r} pubkey length is {len(pubkey)}, expected 64 hex chars. "
|
|
115
|
+
f"Likely placeholder — registry entry must be filled in before release."
|
|
116
|
+
)
|
|
117
|
+
try:
|
|
118
|
+
int(pubkey, 16)
|
|
119
|
+
except ValueError as e:
|
|
120
|
+
raise UnknownLicenseKid(
|
|
121
|
+
f"kid={kid!r} pubkey is not valid hex: {e}. "
|
|
122
|
+
f"Registry entry may still contain a placeholder."
|
|
123
|
+
) from e
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""Canonical label registries for all Capacium surfaces.
|
|
2
|
+
|
|
3
|
+
These dicts serve as single sources of truth — all UIs, badges, APIs, and CLI
|
|
4
|
+
surfaces derive their display labels from these exactly maps.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
RESOURCE_KIND_LABELS = {
|
|
8
|
+
"skill": "Skill",
|
|
9
|
+
"mcp-server": "MCP Server",
|
|
10
|
+
"bundle": "Bundle",
|
|
11
|
+
"tool": "Tool",
|
|
12
|
+
"prompt": "Prompt",
|
|
13
|
+
"template": "Template",
|
|
14
|
+
"workflow": "Workflow",
|
|
15
|
+
"connector-pack": "Connector Pack",
|
|
16
|
+
"operator": "Operator",
|
|
17
|
+
"checkpoint": "Checkpoint",
|
|
18
|
+
"policy": "Policy",
|
|
19
|
+
"resource": "Resource",
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
OPERATOR_TYPE_LABELS = {
|
|
23
|
+
"ai": "AI",
|
|
24
|
+
"human": "Human",
|
|
25
|
+
"hybrid": "Hybrid",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
INSTALL_STATUS_LABELS = {
|
|
29
|
+
"not_installed": "Not Installed",
|
|
30
|
+
"installing": "Installing",
|
|
31
|
+
"installed": "Installed",
|
|
32
|
+
"failed": "Failed",
|
|
33
|
+
"update_available": "Update Available",
|
|
34
|
+
"removed": "Removed",
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
TRUST_BADGES = {
|
|
38
|
+
"discovered": "Discovered",
|
|
39
|
+
"pending_review": "Pending Review",
|
|
40
|
+
"verified": "Verified",
|
|
41
|
+
"signed": "Signed",
|
|
42
|
+
"deprecated": "Deprecated",
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def get_kind_label(kind: str) -> str:
|
|
47
|
+
"""Return the human-readable label for a capability kind.
|
|
48
|
+
|
|
49
|
+
Falls back to the raw string if the kind is unknown.
|
|
50
|
+
"""
|
|
51
|
+
return RESOURCE_KIND_LABELS.get(kind, kind)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def get_operator_type_label(op_type: str) -> str:
|
|
55
|
+
"""Return the human-readable label for an operator type.
|
|
56
|
+
|
|
57
|
+
Falls back to the raw string if the type is unknown.
|
|
58
|
+
"""
|
|
59
|
+
return OPERATOR_TYPE_LABELS.get(op_type, op_type)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def get_install_status_label(status: str) -> str:
|
|
63
|
+
"""Return the human-readable label for an install status.
|
|
64
|
+
|
|
65
|
+
Falls back to the raw string if the status is unknown.
|
|
66
|
+
"""
|
|
67
|
+
return INSTALL_STATUS_LABELS.get(status, status)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_trust_badge(state: str) -> str:
|
|
71
|
+
"""Return the human-readable trust badge label for a trust state.
|
|
72
|
+
|
|
73
|
+
Falls back to the raw string if the state is unknown.
|
|
74
|
+
"""
|
|
75
|
+
return TRUST_BADGES.get(state, state)
|