Skip to content

Commit

Permalink
feat(models): add registries models (#5049)
Browse files Browse the repository at this point in the history
Adds pydantic models for registries.

Signed-off-by: Callahan Kovacs <[email protected]>
  • Loading branch information
mr-cal authored Sep 20, 2024
1 parent 62dacfb commit ad3483f
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 18 deletions.
11 changes: 10 additions & 1 deletion snapcraft/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""Data models for snapcraft."""

from .assertions import Assertion, RegistryAssertion
from .assertions import (
Assertion,
EditableAssertion,
EditableRegistryAssertion,
Registry,
RegistryAssertion,
)
from .manifest import Manifest
from .project import (
MANDATORY_ADOPTABLE_FIELDS,
Expand Down Expand Up @@ -43,12 +49,15 @@
"Component",
"ComponentProject",
"ContentPlug",
"EditableAssertion",
"EditableRegistryAssertion",
"GrammarAwareProject",
"Hook",
"Lint",
"Manifest",
"Platform",
"Project",
"Registry",
"RegistryAssertion",
"SnapcraftBuildPlanner",
"Socket",
Expand Down
75 changes: 64 additions & 11 deletions snapcraft/models/assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,82 @@
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

"""Models for assertion sets."""
"""Assertion models."""

from typing import Any, Literal
from typing import Literal

import pydantic
from craft_application import models
from typing_extensions import Self


class RegistryAssertion(models.CraftBaseModel):
"""Data model for a registry assertion."""
class Registry(models.CraftBaseModel):
"""Access and data definitions for a specific facet of a snap or system."""

request: str | None = None
"""Optional dot-separated path to access the field."""

storage: str
"""Dot-separated storage path."""

access: Literal["read", "write", "read-write"] | None = None
"""Access permissions for the field."""

content: list[Self] | None = None
"""Optional nested rules."""


class Rules(models.CraftBaseModel):
"""A list of registries for a particular view."""

rules: list[Registry]


class EditableRegistryAssertion(models.CraftBaseModel):
"""Subset of a registries assertion that can be edited by the user."""

account_id: str
authority_id: str
body: dict[str, Any] | str | None = None
body_length: str | None = None
"""Issuer of the registry assertion and owner of the signing key."""

name: str
revision: int = 0
sign_key_sha3_384: str | None = None
summary: str | None = None
timestamp: str
revision: int | None = 0

views: dict[str, Rules]
"""A map of logical views of how the storage is accessed."""

body: str | None = None
"""A JSON schema that defines the storage structure."""


class RegistryAssertion(EditableRegistryAssertion):
"""A full registries assertion containing editable and non-editable fields."""

type: Literal["registry"]
views: dict[str, Any]

authority_id: str
"""Issuer of the registry assertion and owner of the signing key."""

timestamp: str
"""Timestamp of when the assertion was issued."""

body_length: str | None = None
"""Length of the body field."""

sign_key_sha3_384: str | None = None
"""Signing key ID."""


class RegistriesList(models.CraftBaseModel):
"""A list of registry assertions."""

registry_list: list[RegistryAssertion] = pydantic.Field(default_factory=list)


# this will be a union for validation sets and registries once
# validation sets are migrated from the legacy codebase
Assertion = RegistryAssertion

# this will be a union for editable validation sets and editable registries once
# validation sets are migrated from the legacy codebase
EditableAssertion = EditableRegistryAssertion
93 changes: 87 additions & 6 deletions tests/unit/models/test_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,92 @@

"""Tests for Assertion models."""

from snapcraft.models import EditableRegistryAssertion, Registry, RegistryAssertion

def test_assertion_defaults(fake_registry_assertion_data, check):

def test_registry_defaults(check):
"""Test default values of the Registry model."""
registry = Registry.unmarshal({"storage": "test-storage"})

check.is_none(registry.request)
check.is_none(registry.access)
check.is_none(registry.content)


def test_registry_nested(check):
"""Test that nested registries are supported."""
registry = Registry.unmarshal(
{
"request": "test-request",
"storage": "test-storage",
"access": "read",
"content": [
{
"request": "nested-request",
"storage": "nested-storage",
"access": "write",
}
],
}
)

check.equal(registry.request, "test-request")
check.equal(registry.storage, "test-storage")
check.equal(registry.access, "read")
check.equal(
registry.content,
[Registry(request="nested-request", storage="nested-storage", access="write")],
)


def test_editable_registry_assertion_defaults(check):
"""Test default values of the EditableRegistryAssertion model."""
assertion = EditableRegistryAssertion.unmarshal(
{
"account_id": "test-account-id",
"name": "test-registry",
"views": {
"wifi-setup": {
"rules": [
{
"storage": "wifi.ssids",
}
]
}
},
}
)

check.is_none(assertion.summary)
check.equal(assertion.revision, 0)
check.is_none(assertion.body)


def test_registry_assertion_defaults(check):
"""Test default values of the RegistryAssertion model."""
check.equal(fake_registry_assertion_data.body, None)
check.equal(fake_registry_assertion_data.body_length, None)
check.equal(fake_registry_assertion_data.sign_key_sha3_384, None)
check.equal(fake_registry_assertion_data.summary, None)
check.equal(fake_registry_assertion_data.revision, 0)
assertion = RegistryAssertion.unmarshal(
{
"account_id": "test-account-id",
"authority_id": "test-authority-id",
"name": "test-registry",
"timestamp": "2024-01-01T10:20:30Z",
"type": "registry",
"views": {
"wifi-setup": {
"rules": [
{
"access": "read-write",
"request": "ssids",
"storage": "wifi.ssids",
}
]
}
},
}
)

check.is_none(assertion.body)
check.is_none(assertion.body_length)
check.is_none(assertion.sign_key_sha3_384)
check.is_none(assertion.summary)
check.equal(assertion.revision, 0)

0 comments on commit ad3483f

Please sign in to comment.