Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
2fdc76e
Create a release preparation script
gilles-peskine-arm Oct 27, 2025
01f26cd
Fix absolute path in generated file
gilles-peskine-arm Oct 27, 2025
c6b1c73
Silence warning about timezone in datetime object
gilles-peskine-arm Oct 27, 2025
b67d2e2
Create release archive
gilles-peskine-arm Oct 27, 2025
22c50c3
Release preparation: assemble changelog
gilles-peskine-arm Oct 27, 2025
81e4bdb
Recognize an empty version section
gilles-peskine-arm Oct 27, 2025
436340b
Release preparation: bump version
gilles-peskine-arm Oct 27, 2025
daedb51
Create draft release notes
gilles-peskine-arm Oct 27, 2025
e9256ed
Instantiate all steps before starting to run one
gilles-peskine-arm Oct 28, 2025
8f4a3ad
Step.edit_file now reports whether it made a change
gilles-peskine-arm Oct 28, 2025
011caf4
Error out if an invalid step name is specified
gilles-peskine-arm Oct 28, 2025
6efb2c2
Better error message if there are uncommitted changes
gilles-peskine-arm Oct 29, 2025
cd957f3
files_are_clean: also consider changes that might be in the index
gilles-peskine-arm Oct 29, 2025
7b6d3ed
Change the version argument to --release-version/-r
gilles-peskine-arm Oct 29, 2025
8c511b2
Add short options for common options
gilles-peskine-arm Oct 29, 2025
5453da7
Add --only-step option (short: -s)
gilles-peskine-arm Oct 29, 2025
9106387
Put default artifact directory under the source tree
gilles-peskine-arm Oct 29, 2025
d181a35
Move git submodule gathering to the Info class
gilles-peskine-arm Oct 29, 2025
c604eec
prepare_release: Support for MLDSA submodule
minosgalanakis Mar 5, 2026
c4c03de
Note the need for git >=2.40.0
gilles-peskine-arm Jul 3, 2026
22092a6
Add experimental --ignore-submodules option
gilles-peskine-arm Jul 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