Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
62d48b6
Create a release preparation script
gilles-peskine-arm Oct 27, 2025
8a23efe
Fix absolute path in generated file
gilles-peskine-arm Oct 27, 2025
b1fe962
Silence warning about timezone in datetime object
gilles-peskine-arm Oct 27, 2025
ec08b35
Create release archive
gilles-peskine-arm Oct 27, 2025
de686b6
Release preparation: assemble changelog
gilles-peskine-arm Oct 27, 2025
b76dda8
Recognize an empty version section
gilles-peskine-arm Oct 27, 2025
e63e602
Release preparation: bump version
gilles-peskine-arm Oct 27, 2025
ea3500b
Create draft release notes
gilles-peskine-arm Oct 27, 2025
904f728
Instantiate all steps before starting to run one
gilles-peskine-arm Oct 28, 2025
3888070
Step.edit_file now reports whether it made a change
gilles-peskine-arm Oct 28, 2025
7c857e7
Error out if an invalid step name is specified
gilles-peskine-arm Oct 28, 2025
ccf9bc3
Better error message if there are uncommitted changes
gilles-peskine-arm Oct 29, 2025
ce09df6
files_are_clean: also consider changes that might be in the index
gilles-peskine-arm Oct 29, 2025
c3ffdc4
Change the version argument to --release-version/-r
gilles-peskine-arm Oct 29, 2025
7514b36
Add short options for common options
gilles-peskine-arm Oct 29, 2025
d91024c
Add --only-step option (short: -s)
gilles-peskine-arm Oct 29, 2025
3b9aa49
Put default artifact directory under the source tree
gilles-peskine-arm Oct 29, 2025
69d6b4f
Move git submodule gathering to the Info class
gilles-peskine-arm Oct 29, 2025
085fac9
prepare_release: Support for MLDSA submodule
minosgalanakis Mar 5, 2026
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 data_files/test_certs.h.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

{% for mode, name, value in macros %}
{% if mode == 'string' %}
/* This is taken from {{value}}. */
/* This is taken from {{data_dir}}/{{value}}. */
/* BEGIN FILE string macro {{name}} {{value}} */
#define {{name}}{{ '\\' | put_to_column(position=80-9-name|length)}}
{% for line in value | read_lines %}
Expand All @@ -21,7 +21,7 @@
/* END FILE */
{% endif %}
{% if mode == 'binary' %}
/* This is generated from {{value}}. */
/* This is generated from {{data_dir}}/{{value}}. */
/* BEGIN FILE binary macro {{name}} {{value}} */
#define {{name}} {% raw -%} { {%- endraw %} {{ '\\' | put_to_column(position=80-11-name|length)}}
{% for line in value | read_as_c_array %}
Expand Down
10 changes: 6 additions & 4 deletions scripts/assemble_changelog.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def is_released_version(cls, title):
# Look for an incomplete release date
return not re.search(r'[0-9x]{4}-[0-9x]{2}-[0-9x]?x', title)

_top_version_re = re.compile(r'(?:\A|\n)(=[^\n]*\n+)(.*?\n)(?:=|$)',
_top_version_re = re.compile(r'(?:\A|\n)(=[^\n]*\n)(.*?)(?:\n=|\Z)',
re.DOTALL)
_name_re = re.compile(r'=\s(.*)\s[0-9x]+\.', re.DOTALL)
@classmethod
Expand All @@ -126,7 +126,7 @@ def extract_top_version(cls, changelog_file_content):
top_version_start = m.start(1)
top_version_end = m.end(2)
top_version_title = m.group(1)
top_version_body = m.group(2)
top_version_body = m.group(2).strip('\n') + '\n'
name = re.match(cls._name_re, top_version_title).group(1)
if cls.is_released_version(top_version_title):
top_version_end = top_version_start
Expand All @@ -136,11 +136,12 @@ def extract_top_version(cls, changelog_file_content):
top_version_title, top_version_body,
changelog_file_content[top_version_end:])

_newlines_only_re = re.compile(r'\n*\Z')
_category_title_re = re.compile(r'(^\w.*)\n+', re.MULTILINE)
@classmethod
def split_categories(cls, version_body):
"""A category title is a line with the title in column 0."""
if not version_body:
if cls._newlines_only_re.match(version_body):
return []
title_matches = list(re.finditer(cls._category_title_re, version_body))
if not title_matches or title_matches[0].start() != 0:
Expand Down Expand Up @@ -341,7 +342,8 @@ def commit_timestamp(commit_id):
text = subprocess.check_output(['git', 'show', '-s',
'--format=%ct',
commit_id])
return datetime.datetime.utcfromtimestamp(int(text))
return datetime.datetime.fromtimestamp(int(text),
datetime.timezone.utc)

@staticmethod
def file_timestamp(filename):
Expand Down
72 changes: 37 additions & 35 deletions scripts/generate_test_cert_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,40 +16,40 @@
from mbedtls_framework.build_tree import guess_project_root

TESTS_DIR = os.path.join(guess_project_root(), 'tests')
FRAMEWORK_DIR = os.path.join(guess_project_root(), 'framework')

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not simply strip it using relpath?

FRAMEWORK_DIR = os.path.join(guess_project_root(), 'framework')
FRAMEWORK_DIR = os.path.relpath(FRAMEWORK_DIR, start=os.getcwd())

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do all the work to construct and deconstruct a path when we already know that the end result must be 'framework'? The path is where the files are located relative to the root of the project, not related to the current directory.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about a compromise of 'os.path.join('./', 'framework')' ?

@gilles-peskine-arm gilles-peskine-arm Oct 29, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's still wrong, isn't it? It would be .\framework on Windows, AFAIK. But we want a reproducible path. What's wrong with writing 'framework' when we mean 'framework'?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Mind you, there may be other occurrences of os.path.join that need fixing if we want to have the same output on Windows. I haven't gone and fixed those and I don't want to extend the scope here to Windows support.)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No please don't :) I doubt we will be spinning windows executors to build a release

DATA_FILES_PATH = os.path.join(FRAMEWORK_DIR, 'data_files')
DATA_DIR_RELATIVE = 'framework/data_files'
DATA_DIR_ABSOLUTE = os.path.join(guess_project_root(), DATA_DIR_RELATIVE)

INPUT_ARGS = [
("string", "TEST_CA_CRT_EC_PEM", DATA_FILES_PATH + "/test-ca2.crt"),
("binary", "TEST_CA_CRT_EC_DER", DATA_FILES_PATH + "/test-ca2.crt.der"),
("string", "TEST_CA_KEY_EC_PEM", DATA_FILES_PATH + "/test-ca2.key.enc"),
("string", "TEST_CA_CRT_EC_PEM", "test-ca2.crt"),
("binary", "TEST_CA_CRT_EC_DER", "test-ca2.crt.der"),
("string", "TEST_CA_KEY_EC_PEM", "test-ca2.key.enc"),
("password", "TEST_CA_PWD_EC_PEM", "PolarSSLTest"),
("binary", "TEST_CA_KEY_EC_DER", DATA_FILES_PATH + "/test-ca2.key.der"),
("string", "TEST_CA_CRT_RSA_SHA256_PEM", DATA_FILES_PATH + "/test-ca-sha256.crt"),
("binary", "TEST_CA_CRT_RSA_SHA256_DER", DATA_FILES_PATH + "/test-ca-sha256.crt.der"),
("string", "TEST_CA_CRT_RSA_SHA1_PEM", DATA_FILES_PATH + "/test-ca-sha1.crt"),
("binary", "TEST_CA_CRT_RSA_SHA1_DER", DATA_FILES_PATH + "/test-ca-sha1.crt.der"),
("string", "TEST_CA_KEY_RSA_PEM", DATA_FILES_PATH + "/test-ca.key"),
("binary", "TEST_CA_KEY_EC_DER", "test-ca2.key.der"),
("string", "TEST_CA_CRT_RSA_SHA256_PEM", "test-ca-sha256.crt"),
("binary", "TEST_CA_CRT_RSA_SHA256_DER", "test-ca-sha256.crt.der"),
("string", "TEST_CA_CRT_RSA_SHA1_PEM", "test-ca-sha1.crt"),
("binary", "TEST_CA_CRT_RSA_SHA1_DER", "test-ca-sha1.crt.der"),
("string", "TEST_CA_KEY_RSA_PEM", "test-ca.key"),
("password", "TEST_CA_PWD_RSA_PEM", "PolarSSLTest"),
("binary", "TEST_CA_KEY_RSA_DER", DATA_FILES_PATH + "/test-ca.key.der"),
("string", "TEST_SRV_CRT_EC_PEM", DATA_FILES_PATH + "/server5.crt"),
("binary", "TEST_SRV_CRT_EC_DER", DATA_FILES_PATH + "/server5.crt.der"),
("string", "TEST_SRV_KEY_EC_PEM", DATA_FILES_PATH + "/server5.key"),
("binary", "TEST_SRV_KEY_EC_DER", DATA_FILES_PATH + "/server5.key.der"),
("string", "TEST_SRV_CRT_RSA_SHA256_PEM", DATA_FILES_PATH + "/server2-sha256.crt"),
("binary", "TEST_SRV_CRT_RSA_SHA256_DER", DATA_FILES_PATH + "/server2-sha256.crt.der"),
("string", "TEST_SRV_CRT_RSA_SHA1_PEM", DATA_FILES_PATH + "/server2.crt"),
("binary", "TEST_SRV_CRT_RSA_SHA1_DER", DATA_FILES_PATH + "/server2.crt.der"),
("string", "TEST_SRV_KEY_RSA_PEM", DATA_FILES_PATH + "/server2.key"),
("binary", "TEST_SRV_KEY_RSA_DER", DATA_FILES_PATH + "/server2.key.der"),
("string", "TEST_CLI_CRT_EC_PEM", DATA_FILES_PATH + "/cli2.crt"),
("binary", "TEST_CLI_CRT_EC_DER", DATA_FILES_PATH + "/cli2.crt.der"),
("string", "TEST_CLI_KEY_EC_PEM", DATA_FILES_PATH + "/cli2.key"),
("binary", "TEST_CLI_KEY_EC_DER", DATA_FILES_PATH + "/cli2.key.der"),
("string", "TEST_CLI_CRT_RSA_PEM", DATA_FILES_PATH + "/cli-rsa-sha256.crt"),
("binary", "TEST_CLI_CRT_RSA_DER", DATA_FILES_PATH + "/cli-rsa-sha256.crt.der"),
("string", "TEST_CLI_KEY_RSA_PEM", DATA_FILES_PATH + "/cli-rsa.key"),
("binary", "TEST_CLI_KEY_RSA_DER", DATA_FILES_PATH + "/cli-rsa.key.der"),
("binary", "TEST_CA_KEY_RSA_DER", "test-ca.key.der"),
("string", "TEST_SRV_CRT_EC_PEM", "server5.crt"),
("binary", "TEST_SRV_CRT_EC_DER", "server5.crt.der"),
("string", "TEST_SRV_KEY_EC_PEM", "server5.key"),
("binary", "TEST_SRV_KEY_EC_DER", "server5.key.der"),
("string", "TEST_SRV_CRT_RSA_SHA256_PEM", "server2-sha256.crt"),
("binary", "TEST_SRV_CRT_RSA_SHA256_DER", "server2-sha256.crt.der"),
("string", "TEST_SRV_CRT_RSA_SHA1_PEM", "server2.crt"),
("binary", "TEST_SRV_CRT_RSA_SHA1_DER", "server2.crt.der"),
("string", "TEST_SRV_KEY_RSA_PEM", "server2.key"),
("binary", "TEST_SRV_KEY_RSA_DER", "server2.key.der"),
("string", "TEST_CLI_CRT_EC_PEM", "cli2.crt"),
("binary", "TEST_CLI_CRT_EC_DER", "cli2.crt.der"),
("string", "TEST_CLI_KEY_EC_PEM", "cli2.key"),
("binary", "TEST_CLI_KEY_EC_DER", "cli2.key.der"),
("string", "TEST_CLI_CRT_RSA_PEM", "cli-rsa-sha256.crt"),
("binary", "TEST_CLI_CRT_RSA_DER", "cli-rsa-sha256.crt.der"),
("string", "TEST_CLI_KEY_RSA_PEM", "cli-rsa.key"),
("binary", "TEST_CLI_KEY_RSA_DER", "cli-rsa.key.der"),
]

def main():
Expand All @@ -62,7 +62,8 @@ def main():
if args.list_dependencies:
files_list = [arg[2] for arg in INPUT_ARGS
if arg[0] != "password"]
print(" ".join(files_list))
print(" ".join(os.path.join(DATA_DIR_RELATIVE, filename)
for filename in files_list))
return

generate(INPUT_ARGS, output=args.output)
Expand All @@ -71,20 +72,20 @@ def main():
def generate(values=[], output=None):
"""Generate C header file.
"""
template_loader = jinja2.FileSystemLoader(DATA_FILES_PATH)
template_loader = jinja2.FileSystemLoader(DATA_DIR_ABSOLUTE)
template_env = jinja2.Environment(
loader=template_loader, lstrip_blocks=True, trim_blocks=True,
keep_trailing_newline=True)

def read_as_c_array(filename):
with open(filename, 'rb') as f:
with open(os.path.join(DATA_DIR_ABSOLUTE, filename), 'rb') as f:
data = f.read(12)
while data:
yield ', '.join(['{:#04x}'.format(b) for b in data])
data = f.read(12)

def read_lines(filename):
with open(filename) as f:
with open(os.path.join(DATA_DIR_ABSOLUTE, filename)) as f:
try:
for line in f:
yield line.strip()
Expand All @@ -102,7 +103,8 @@ def put_to_column(value, position=0):
template = template_env.get_template('test_certs.h.jinja2')

with open(output, 'w') as f:
f.write(template.render(macros=values))
f.write(template.render(data_dir=DATA_DIR_RELATIVE,
macros=values))


if __name__ == '__main__':
Expand Down
Loading