Skip to content

Commit

Permalink
Merge branch 'main' into split-test-running-in-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
MVrachev authored Mar 22, 2024
2 parents d296c13 + 10fe7be commit 8653958
Show file tree
Hide file tree
Showing 20 changed files with 527 additions and 135 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
needs: functional-tests
steps:
- name: Login to GitHub Container Registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
Expand All @@ -69,7 +69,7 @@ jobs:
docker push ghcr.io/repository-service-tuf/repository-service-tuf-api:latest
- name: Publish GitHub Release
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844
uses: softprops/action-gh-release@9d7c94cfd0a1f3ed45544c887983e9fa900f0564
with:
name: ${{ github.ref_name }}
tag_name: ${{ github.ref }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish_container.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ jobs:
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226
uses: docker/setup-buildx-action@0d103c3126aa41d772a8362f6aa67afac040f80c

- name: Login to GitHub Container Registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0
with:
context: .
push: true
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish_docker_dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,17 @@ jobs:
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226
uses: docker/setup-buildx-action@0d103c3126aa41d772a8362f6aa67afac040f80c

- name: Login to GitHub Container Registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d
uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0
with:
context: .
push: true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test_docker_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ jobs:
uses: docker/setup-qemu-action@68827325e0b33c7199eb31dd4e31fbe9023e06e3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226
uses: docker/setup-buildx-action@0d103c3126aa41d772a8362f6aa67afac040f80c

- name: Build and push
uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56
uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0
with:
context: .
push: false
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-pre-commit-hooks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
run: |
make tests
- name: Create Pull Request
uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50
uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "build: Update pre-commit hooks"
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/update-python-deps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
run: |
make tests
- name: Create Pull Request
uses: peter-evans/create-pull-request@b1ddad2c994a25fbc81a28b3ec0e368bb2021c50
uses: peter-evans/create-pull-request@70a41aba780001da0a30141984ae2a0c95d8704e
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "build: Update Python dependencies"
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ repos:
- id: isort
args: [-l79, --profile, black, --check, --diff]
- repo: https://github.com/psf/black
rev: '24.2.0'
rev: '24.3.0'
hooks:
- id: black
args: [-l79, --check, --diff, .]
- repo: https://github.com/PyCQA/bandit
rev: '1.7.7'
rev: '1.7.8'
hooks:
- id: bandit
args: ["-r", "repository_service_tuf_api"]
Expand Down
160 changes: 80 additions & 80 deletions Pipfile.lock

Large diffs are not rendered by default.

39 changes: 38 additions & 1 deletion docs/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"info": {
"title": "Repository Service for TUF API",
"description": "Repository Service for TUF Rest API",
"version": "0.12.0b1"
"version": "0.13.0b1"
},
"paths": {
"/api/v1/bootstrap/": {
Expand Down Expand Up @@ -734,6 +734,29 @@
"message": "Bootstrap accepted."
}
},
"DelegatedRole": {
"properties": {
"expiration": {
"type": "integer",
"exclusiveMinimum": 0.0,
"title": "Expiration"
},
"path_patterns": {
"items": {
"type": "string"
},
"type": "array",
"minItems": 1,
"title": "Path Patterns"
}
},
"type": "object",
"required": [
"expiration",
"path_patterns"
],
"title": "DelegatedRole"
},
"DeleteData": {
"properties": {
"task_id": {
Expand Down Expand Up @@ -1356,6 +1379,20 @@
"type": "null"
}
]
},
"delegated_roles": {
"anyOf": [
{
"additionalProperties": {
"$ref": "#/components/schemas/DelegatedRole"
},
"type": "object"
},
{
"type": "null"
}
],
"title": "Delegated Roles"
}
},
"type": "object",
Expand Down
2 changes: 1 addition & 1 deletion repository_service_tuf_api/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
#
# SPDX-License-Identifier: MIT

version = "0.12.0b1"
version = "0.13.0b1"
copyright = "Copyright (c) 2024 Repository Service for TUF Contributors"
author = "Kairo de Araujo"
61 changes: 57 additions & 4 deletions repository_service_tuf_api/bootstrap.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@

import json
import logging
import re
import time
from datetime import datetime
from threading import Thread
from typing import Dict, Literal, Optional
from typing import Any, Dict, List, Optional

from fastapi import HTTPException, status
from pydantic import BaseModel, ConfigDict, Field
from pydantic import BaseModel, ConfigDict, Field, model_validator

from repository_service_tuf_api import (
bootstrap_state,
Expand All @@ -22,10 +23,13 @@
)
from repository_service_tuf_api.common_models import (
BaseErrorResponse,
Roles,
TUFMetadata,
)

# Pattern of allowed names to be used by custom target delegated roles
DELEGATED_NAMES_PATTERN = "[a-zA-Z0-9_-]+"


with open("tests/data_examples/bootstrap/payload_bins.json") as f:
content = f.read()
payload_example = json.loads(content)
Expand All @@ -39,12 +43,61 @@ class BinsRole(Role):
number_of_delegated_bins: int = Field(gt=1, lt=16385)


class DelegatedRole(Role):
# Note: No validation is required for path_patterns as these patterns are
# only used to distribute artifacts. No files are created based on them.
path_patterns: List[str] = Field(min_length=1)

@model_validator(mode="before")
@classmethod
def validate_path_patterns(cls, values: Dict[str, Any]):
path_patterns = values.get("path_patterns")
if any(len(pattern) < 1 for pattern in path_patterns):
raise ValueError("No empty strings are allowed as path patterns")

return values


class RolesData(BaseModel):
root: Role
targets: Role
snapshot: Role
timestamp: Role
bins: Optional[BinsRole] = Field(default=None)
delegated_roles: Optional[Dict[str, DelegatedRole]] = Field(default=None)

@model_validator(mode="before")
@classmethod
def validate_delegations(cls, values: Dict[str, Any]) -> Dict[str, Any]:
bins = values.get("bins")
delegated_roles = values.get("delegated_roles")
if (bins is None and delegated_roles is None) or (
bins is not None and delegated_roles is not None
):
err_msg = "Exactly one of 'bins' and 'delegated_roles' must be set"
raise ValueError(err_msg)

return values

@model_validator(mode="before")
@classmethod
def validate_delegated_roles_names(
cls, values: Dict[str, Any]
) -> Dict[str, Any]:
# Validation of custom target delegated names is required as otherwise
# an attacker can use a custom target name to point to a specific place
# in a file system and override a file or cause unexpected behavior.
delegated_roles = values.get("delegated_roles")
if delegated_roles is not None:
# The keys of the delegated_roles dict are the names of the roles.
for role_name in delegated_roles.keys():
if re.fullmatch(DELEGATED_NAMES_PATTERN, role_name) is None:
raise ValueError(
f"Delegated custom target name {role_name} not allowed"
" Only a-z, A-Z, 0-9, - and _ characters can be used"
)

return values


class Settings(BaseModel):
Expand All @@ -54,7 +107,7 @@ class Settings(BaseModel):
class BootstrapPayload(BaseModel):
model_config = ConfigDict(json_schema_extra={"example": payload_example})
settings: Settings
metadata: Dict[Literal[Roles.ROOT.value], TUFMetadata]
metadata: Dict[str, TUFMetadata]
timeout: int | None = Field(default=300, description="Timeout in seconds")


Expand Down
4 changes: 0 additions & 4 deletions repository_service_tuf_api/common_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,6 @@ class Roles(Enum):
def values() -> List[str]:
return Literal["root", "targets", "snapshot", "timestamp", "bins"]

@staticmethod
def online_roles_values() -> List[str]:
return Literal["targets", "snapshot", "timestamp", "bins"]


class BaseErrorResponse(BaseModel):
error: str = Field(description="Error message")
Expand Down
25 changes: 13 additions & 12 deletions repository_service_tuf_api/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,6 @@
repository_metadata,
settings_repository,
)
from repository_service_tuf_api.common_models import Roles

with open("tests/data_examples/config/settings.json") as f:
content = f.read()
example_settings = json.loads(content)

with open("tests/data_examples/config/update_settings.json") as f:
content = f.read()
example_update_settings = json.loads(content)


class PutData(BaseModel):
Expand All @@ -51,13 +42,18 @@ class PutResponse(BaseModel):

class Settings(BaseModel):
# Only online roles can be dict keys
expiration: Dict[Roles.online_roles_values(), int]
expiration: Dict[str, int]


with open("tests/data_examples/config/update_settings.json") as f:
content = f.read()
put_payload = json.loads(content)


class PutPayload(BaseModel):
model_config = ConfigDict(
json_schema_extra={
"example": example_update_settings,
"example": put_payload,
}
)

Expand Down Expand Up @@ -95,6 +91,11 @@ def put(payload: PutPayload):
return PutResponse(data=data, message="Settings successfully submitted.")


with open("tests/data_examples/config/settings.json") as f:
content = f.read()
example_settings = json.loads(content)


class GetResponse(BaseModel):
model_config = ConfigDict(
json_schema_extra={
Expand All @@ -108,7 +109,7 @@ class GetResponse(BaseModel):
message: str


def get():
def get() -> GetResponse:
bs_state = bootstrap_state()
if bs_state.bootstrap is False:
raise HTTPException(
Expand Down
9 changes: 5 additions & 4 deletions repository_service_tuf_api/targets.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@
repository_metadata,
)

with open("tests/data_examples/targets/payload.json") as f:
content = f.read()
add_payload = json.loads(content)


class ResponseData(BaseModel):
targets: List[str]
Expand Down Expand Up @@ -65,6 +61,11 @@ class Targets(BaseModel):
path: str


with open("tests/data_examples/targets/payload.json") as f:
content = f.read()
add_payload = json.loads(content)


class AddPayload(BaseModel):
"""
POST method required Payload.
Expand Down
Loading

0 comments on commit 8653958

Please sign in to comment.