Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
- name: Set up Python (oldest supported version)
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.10"
python-version: "3.11"
cache: 'pip'
cache-dependency-path: |
requirements/*.txt
Expand All @@ -38,7 +38,7 @@ jobs:
needs: lint-test
strategy:
matrix:
python-version: ["3.10", "3.11", "3.12", "3.13", "3.14"]
python-version: ["3.11", "3.12", "3.13", "3.14", "3.15"]
os: [ubuntu-latest]
include:
- python-version: "3.x"
Expand Down
5 changes: 5 additions & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Unreleased

### Changed

* Add Python 3.15 to tested versions, remove 3.10 from tested versions.
Require at least 3.11

## v7.0.1

### Fixed
Expand Down
6 changes: 2 additions & 4 deletions examples/manual_repo/basic_repo.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@

import os
import tempfile
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta
from pathlib import Path

from securesystemslib.signer import CryptoSigner, Signer
Expand All @@ -50,9 +50,7 @@

def _in(days: float) -> datetime:
"""Adds 'days' to now and returns datetime object w/o microseconds."""
return datetime.now(timezone.utc).replace(microsecond=0) + timedelta(
days=days
)
return datetime.now(UTC).replace(microsecond=0) + timedelta(days=days)


# Create top-level metadata
Expand Down
6 changes: 2 additions & 4 deletions examples/manual_repo/hashed_bin_delegation.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import hashlib
import os
import tempfile
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import TYPE_CHECKING

Expand All @@ -45,9 +45,7 @@

def _in(days: float) -> datetime:
"""Adds 'days' to now and returns datetime object w/o microseconds."""
return datetime.now(timezone.utc).replace(microsecond=0) + timedelta(
days=days
)
return datetime.now(UTC).replace(microsecond=0) + timedelta(days=days)


roles: dict[str, Metadata[Targets]] = {}
Expand Down
6 changes: 2 additions & 4 deletions examples/manual_repo/succinct_hash_bin_delegations.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import math
import os
import tempfile
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta
from pathlib import Path

from securesystemslib.signer import CryptoSigner
Expand Down Expand Up @@ -95,9 +95,7 @@
# NOTE: See "Targets" and "Targets delegation" paragraphs in 'basic_repo.py'
# example for more details about the Targets object.

expiration_date = datetime.now(timezone.utc).replace(microsecond=0) + timedelta(
days=7
)
expiration_date = datetime.now(UTC).replace(microsecond=0) + timedelta(days=7)
targets = Metadata(Targets(expires=expiration_date))

succinct_roles = SuccinctRoles(
Expand Down
4 changes: 2 additions & 2 deletions examples/repository/_simplerepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import json
import logging
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta

from securesystemslib.signer import CryptoSigner, Key, Signer

Expand Down Expand Up @@ -130,7 +130,7 @@ def open(self, role: str) -> Metadata:
def close(self, role: str, md: Metadata) -> None:
"""Store a version of metadata. Handle version bumps, expiry, signing"""
md.signed.version += 1
md.signed.expires = datetime.now(timezone.utc) + self.expiry_period
md.signed.expires = datetime.now(UTC) + self.expiry_period

md.signatures.clear()
for signer in self.signer_cache[role]:
Expand Down
4 changes: 2 additions & 2 deletions examples/uploader/_localrepo.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import json
import logging
import os
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta

from securesystemslib.signer import CryptoSigner, Signer
from urllib3 import request
Expand Down Expand Up @@ -87,7 +87,7 @@ def close(self, role_name: str, md: Metadata) -> None:
signer = Signer.from_priv_key_uri(uri, public_key)

md.signed.version += 1
md.signed.expires = datetime.now(timezone.utc) + self.expiry_period
md.signed.expires = datetime.now(UTC) + self.expiry_period

md.sign(signer, append=False)

Expand Down
4 changes: 2 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description = "A secure updater framework for Python"
readme = "README.md"
license = "Apache-2.0 OR MIT"
license-files = ["LICENSE", "LICENSE-MIT"]
requires-python = ">=3.10"
requires-python = ">=3.11"
authors = [
{ email = "theupdateframework@googlegroups.com" },
]
Expand All @@ -31,11 +31,11 @@ classifiers = [
"Operating System :: POSIX :: Linux",
"Programming Language :: Python",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Programming Language :: Python :: 3.14",
"Programming Language :: Python :: 3.15",
"Programming Language :: Python :: Implementation :: CPython",
"Topic :: Security",
"Topic :: Software Development",
Expand Down
4 changes: 2 additions & 2 deletions tests/generated_data/generate_md.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import os
import sys
from datetime import datetime, timezone
from datetime import UTC, datetime

from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PrivateKey
from securesystemslib.signer import CryptoSigner, Signer, SSlibKey
Expand Down Expand Up @@ -55,7 +55,7 @@
private_key = Ed25519PrivateKey.from_private_bytes(private_values[index])
signers.append(CryptoSigner(private_key, key))

EXPIRY = datetime(2050, 1, 1, tzinfo=timezone.utc)
EXPIRY = datetime(2050, 1, 1, tzinfo=UTC)

SERIALIZER = JSONSerializer()

Expand Down
2 changes: 1 addition & 1 deletion tests/repository_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def __init__(self) -> None:

self.fetch_tracker = FetchTracker()

now = datetime.datetime.now(datetime.timezone.utc)
now = datetime.datetime.now(datetime.UTC)
self.safe_expiry = now.replace(microsecond=0) + datetime.timedelta(
days=30
)
Expand Down
8 changes: 4 additions & 4 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import tempfile
import unittest
from copy import copy, deepcopy
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta
from pathlib import Path
from typing import ClassVar

Expand Down Expand Up @@ -312,7 +312,7 @@ def test_metadata_signed_is_expired(self) -> None:
snapshot_path = os.path.join(self.repo_dir, "metadata", "snapshot.json")
md = Metadata.from_file(snapshot_path)

expected_expiry = datetime(2030, 1, 1, 0, 0, tzinfo=timezone.utc)
expected_expiry = datetime(2030, 1, 1, 0, 0, tzinfo=UTC)
self.assertEqual(md.signed.expires, expected_expiry)

# Test is_expired with reference_time provided
Expand All @@ -326,10 +326,10 @@ def test_metadata_signed_is_expired(self) -> None:
# Test is_expired without reference_time,
# manipulating md.signed.expires
expires = md.signed.expires
md.signed.expires = datetime.now(timezone.utc)
md.signed.expires = datetime.now(UTC)
is_expired = md.signed.is_expired()
self.assertTrue(is_expired)
md.signed.expires = datetime.now(timezone.utc) + timedelta(days=1)
md.signed.expires = datetime.now(UTC) + timedelta(days=1)
is_expired = md.signed.is_expired()
self.assertFalse(is_expired)
md.signed.expires = expires
Expand Down
4 changes: 2 additions & 2 deletions tests/test_repository.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import sys
import unittest
from collections import defaultdict
from datetime import datetime, timedelta, timezone
from datetime import UTC, datetime, timedelta

from securesystemslib.signer import CryptoSigner, Signer

Expand Down Expand Up @@ -107,7 +107,7 @@ def open(self, role: str) -> Metadata:
def close(self, role: str, md: Metadata) -> None:
"""Store a version of metadata. Handle version bumps, expiry, signing"""
md.signed.version += 1
md.signed.expires = datetime.now(timezone.utc) + self.expiry_period
md.signed.expires = datetime.now(UTC) + self.expiry_period

md.signatures.clear()
for signer in self.signer_cache[role]:
Expand Down
10 changes: 5 additions & 5 deletions tests/test_trusted_metadata_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import os
import sys
import unittest
from datetime import datetime, timezone
from datetime import UTC, datetime
from typing import TYPE_CHECKING, ClassVar

from securesystemslib.signer import Signer
Expand Down Expand Up @@ -299,7 +299,7 @@ def test_update_root_new_root_ver_same_as_trusted_root_ver(self) -> None:

def test_root_expired_final_root(self) -> None:
def root_expired_modifier(root: Root) -> None:
root.expires = datetime(1970, 1, 1, tzinfo=timezone.utc)
root.expires = datetime(1970, 1, 1, tzinfo=UTC)

# intermediate root can be expired
root = self.modify_metadata(Root.type, root_expired_modifier)
Expand Down Expand Up @@ -349,7 +349,7 @@ def bump_snapshot_version(timestamp: Timestamp) -> None:
def test_update_timestamp_expired(self) -> None:
# new_timestamp has expired
def timestamp_expired_modifier(timestamp: Timestamp) -> None:
timestamp.expires = datetime(1970, 1, 1, tzinfo=timezone.utc)
timestamp.expires = datetime(1970, 1, 1, tzinfo=UTC)

# expired intermediate timestamp is loaded but raises
timestamp = self.modify_metadata(
Expand Down Expand Up @@ -426,7 +426,7 @@ def test_update_snapshot_expired_new_snapshot(self) -> None:
self.trusted_set.update_timestamp(self.metadata[Timestamp.type])

def snapshot_expired_modifier(snapshot: Snapshot) -> None:
snapshot.expires = datetime(1970, 1, 1, tzinfo=timezone.utc)
snapshot.expires = datetime(1970, 1, 1, tzinfo=UTC)

# expired intermediate snapshot is loaded but will raise
snapshot = self.modify_metadata(
Expand Down Expand Up @@ -506,7 +506,7 @@ def test_update_targets_expired_new_target(self) -> None:

# new_delegated_target has expired
def target_expired_modifier(target: Targets) -> None:
target.expires = datetime(1970, 1, 1, tzinfo=timezone.utc)
target.expires = datetime(1970, 1, 1, tzinfo=UTC)

targets = self.modify_metadata(Targets.type, target_expired_modifier)
with self.assertRaises(exceptions.ExpiredMetadataError):
Expand Down
15 changes: 7 additions & 8 deletions tests/test_updater_top_level_update.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import sys
import tempfile
import unittest
from datetime import timezone
from pathlib import Path
from typing import TYPE_CHECKING
from unittest.mock import MagicMock, call, patch
Expand Down Expand Up @@ -50,7 +49,7 @@ class TestRefresh(unittest.TestCase):
# set dump_dir to trigger repository state dumps
dump_dir: str | None = None

past_datetime = datetime.datetime.now(timezone.utc).replace(
past_datetime = datetime.datetime.now(datetime.UTC).replace(
microsecond=0
) - datetime.timedelta(days=5)

Expand Down Expand Up @@ -312,7 +311,7 @@ def test_expired_timestamp_version_rollback(self) -> None:
- Second updater refresh performed on day 18:
assert that rollback check uses expired timestamp v1"""

now = datetime.datetime.now(timezone.utc)
now = datetime.datetime.now(datetime.UTC)
self.sim.timestamp.expires = now + datetime.timedelta(days=7)

self.sim.timestamp.version = 2
Expand All @@ -325,7 +324,7 @@ def test_expired_timestamp_version_rollback(self) -> None:
self.sim.timestamp.version = 1

patcher = freezegun.freeze_time(
datetime.datetime.now(timezone.utc) + datetime.timedelta(days=18)
datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=18)
)
# Check that a rollback protection is performed even if
# local timestamp has expired
Expand All @@ -346,7 +345,7 @@ def test_expired_timestamp_snapshot_rollback(self) -> None:
- Second updater refresh performed on day 18:
assert that rollback protection is done with expired timestamp v1"""

now = datetime.datetime.now(timezone.utc)
now = datetime.datetime.now(datetime.UTC)
self.sim.timestamp.expires = now + datetime.timedelta(days=7)

# Bump the snapshot version number to 3
Expand All @@ -362,7 +361,7 @@ def test_expired_timestamp_snapshot_rollback(self) -> None:
self.sim.timestamp.expires = now + datetime.timedelta(days=21)

patcher = freezegun.freeze_time(
datetime.datetime.now(timezone.utc) + datetime.timedelta(days=18)
datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=18)
)
# Assert that rollback protection is done even if
# local timestamp has expired
Expand Down Expand Up @@ -822,7 +821,7 @@ def test_expired_metadata(self) -> None:
- Second updater refresh performed on day 18,
it is successful and timestamp/snapshot final versions are v2"""

now = datetime.datetime.now(timezone.utc)
now = datetime.datetime.now(datetime.UTC)
self.sim.timestamp.expires = now + datetime.timedelta(days=7)

# Make a successful update of valid metadata which stores it in cache
Expand All @@ -835,7 +834,7 @@ def test_expired_metadata(self) -> None:
# Mocking time so that local timestam has expired
# but the new timestamp has not
with freezegun.freeze_time(
datetime.datetime.now(timezone.utc) + datetime.timedelta(days=18)
datetime.datetime.now(datetime.UTC) + datetime.timedelta(days=18)
):
self._run_refresh()

Expand Down
Loading
Loading