初始提交:terminalX 可运行态(M0/M1/M1.5 已真机验证)

- M0: libghostty SSH 终端(渲染/输入/连接)+ 白屏修复(OutputGate) + 会话状态机/自动重连
- M1: tsnet 用户态组网 + SSH-over-tsnet(fd 桥),shell 级真机验证;R5(Go+gvisor+C+++Swift 同进程) retire
- M1.5: tmux -CC 原生 tab(MVP)
- 结构: packages/(TXCore·TXTransport), apps/TerminalX, vendor/(libghostty-spm/libssh2/mbedtls/tsnet-bridge), artifacts/
- 文档: CLAUDE.md + docs/HANDOFF.md(新会话入口)
- 环境: 认证代理→依赖 vendor 本地化;Go 在 ~/.local/go;仅模拟器/未签名
- 待续: M2 mosh, tmux 多 pane, M4 安全(host key/SE)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
kid
2026-07-24 10:20:46 +08:00
commit aa92d0e676
2761 changed files with 803505 additions and 0 deletions

View File

@@ -0,0 +1,149 @@
# Mbed TLS and TF-PSA-Crypto configuration check framework
This document describes the compile-time configuration check framework. The goal of this framework is to detect bad configurations when the library is compiled. It consists of three parts:
* [manually written checks](#manually-written-checks) (since PolarSSL);
* [generated checks](#generated-checks) (since TF-PSA-Crypto 1.0 and Mbed TLS 4.0);
* [validating that some configurations are recognized as bad](#validation) (since TF-PSA-Crypto 1.0 and Mbed TLS 4.0).
## Introduction
### What is a configuration?
A configuration (“config” for short) is a set of macro definitions that are chosen by the user who compiles the library, with defaults provided by the library maintainers. Those definitions may come from:
* the compiler command line (`-D`);
* The subproject's configuration files, if applicable (i.e. TF-PSA-Crypto's config files are part of the Mbed TLS config);
* The project's main configuration file: the macro expansion of `MBEDTLS_CONFIG_FILE` or `TF_PSA_CRYPTO_CONFIG_FILE`, defaulting to `"mbedtls/mbedtls_config.h"` or `"psa/crypto_config.h"` respectively;
* The project's user configuration, given by the macro `MBEDTLS_USER_CONFIG_FILE` or `TF_PSA_CRYPTO_USER_CONFIG_FILE`, if defined.
### Why are configurations bad?
There are several reasons why we might consider a configuration undesirable (“bad”) for short, including:
* The configuration would lead to a compile-time error. We prefer to emit a comprehensible error message, rather than let the user puzzle over e.g. a missing symbol at link time.
* The configuration is technically valid but unlikely to be desirable. For example, enabling ECC support but not at least one curve. Since we don't test such configurations, they may or may not work anyway.
* The configuration is technically valid and should work, but potentially dangerous. For example, building with a weak random generator. In such cases, if the configuration may be accidentally weak, we may want to require the user to an additional “`I_KNOW_WHAT_I_M_DOING`” macro.
* The user defined or undefined a macro which is normally set internally (typically in `*adjust*.h`). This is very likely to lead to internal consistencies, so we would like to reject the attempt.
* The user defined or undefined a macro that used to be meaningful in a previous version of the library, but no longer is. We would like to emit an error that points the user to a replacement, if applicable.
* The user defined a configuration option in the wrong project. A superproject must have the same configuration of the subproject that was used to build the subproject — concretely, setting a crypto option in Mbed TLS to a different value than in TF-PSA-Crypto is very likely to lead to inconsistencies in Mbed TLS.
Some of these cases follow generic patterns that are susceptible for automation (e.g. options removed in the last major release), while others are very ad hoc and need to be defined manually (e.g. at least one of a set). Hence we have both [generated checks](#generated-checks) and [manually written checks](#manually-written-checks).
### When is the configuration checked?
We want to check the configuration when building the library.
Applications are very likely to misbehave if they are built with different compilation options from the library.
It is tempting to check the configuration when building applications: what if the user tried editing the config file after the library was built, or passed different options on the compiler command line?
Users who try to change the configuration are very likely to reach a configuration that's still internally consistent, for example just a few more features, or different sizes. Configuration checks during the application build cannot detect that, since they have no access to the actual library configuration. Hence application-build-time checks would provide very little safety, but a false sense of safety. So since TF-PSA-Crypto 1.0 and Mbed TLS 4.0, we perform the checks only when building the library. (It was different before — see “[Configuration checks up to Mbed TLS 3.x](#configuration-checks-up-to-mbed-tls-3-x)” — but only for historical reasons, because in PolarSSL, all header files were public.)
## Analysis of bad configurations
This section analyses why certain kinds of configurations are bad. Note that not all bad configurations are actually rejected; consult the generator code for details (see “[How the checks are generated](#how-the-checks-are-generated)”).
### Command line definitions
Applications using the library must be built with the same configuration as the library. Otherwise they may make incompatible assumptions leading to undefined behavior at run time. Therefore it is problematic to define configuration options on the compiler command line (`cc -DMBEDTLS_XXX ...`).
The configuration file variables (<code><em>PROJECT</em>\_CONFIG\_FILE</code>, and possibly <code><em>PROJECT</em>\_USER\_CONFIG\_FILE</code>) are exceptions because it makes sense to, for example, compile the library with `MBEDTLS_CONFIG_FILE="../../acme_platform/include/mbedtls_config.h"` (avoiding changes to the source tree and constraints on the include path order) and then install the file as `/usr/include/mbedtls/mbedtls_config.h`. For those, what matters is the content.
The config check generator script makes it easy to detect if an option was set on the compiler command line. However, many embedded projects compile the whole platform with a single set of compiler options, and those options may include some of our config options. So if we reject command line options, we should provide an official way to bypass accept them.
As of TF-PSA-Crypto 1.0 and Mbed TLS 4.0, configuration checks do not treat options set on the command line differently from options set in the config file.
### Derived macros
We derive many macros conditionally from the configuration options, mostly in `*adjust*.h`. (These headers can also define additional options to handle implicit requirements, but that part is not relevant here.) These macros must be consistent with the configuration, otherwise the library may misbehave (e.g. overflow internal buffers).
Thus it is dangerous for derived macros to be set in the configuration file. (We could make it inoffensive by systematically either defining or explicitly undefining each derived macro, but that would be extra burden for which a mistake is easily made.)
Unsetting a derived macro is not dangerous, but won't have any effect since the macro is not set yet. So we can reject it but it isn't particularly important.
We can detect bad setting of derived macros by erroring if they are set after including the config files and before doing the adjustments.
### Subproject options
The superproject (Mbed TLS) reads the configuration of the subproject (TF-PSA-Crypto), but the converse is not true. Therefore:
* Setting a superproject option identically in the subproject and in the superproject is perfectly fine.
* Setting a superproject option only in the subproject is maybe a little weird, but harmless.
* Setting a superproject option to different values in the superproject and in a subproject has a well-defined effect, but is probably a mistake. (Note that for boolean options, setting to off is usually indistinguishable from not setting, but can technically be done with `#undef`.)
* Setting a subproject option in the superproject, except when it was already set (to the same value if applicable), is dangerous. It won't enable the feature and may lead to undefined behavior in the superproject.
* It is also dangerous to set or unset a macro in the superproject's configuration if that macro is a derived one in the subproject.
In Mbed TLS 4.x, there is a high risk that users migrating from Mbed TLS 3.6 will accidentally leave a crypto option in `mbedtls_config.h` instead of moving it to `crypto_config.h`. So we should particularly try to handle this case: macros that were configuration options in Mbed TLS 3.6 and that are now a configuration option or a derived macro in TF-PSA-Crypto.
### Removed options
Users who are upgrading from a previous major version of Mbed TLS (or TF-PSA-Crypto, once TF-PSA-Crypto 2.0 is released) may still attempt to use removed options, if they haven't fully upgraded their configuration file. This will likely not have the intended effect. Worse, if a former option has become an [internal macro that is now derived from other options](#derived-macros), this may result in an inconsistent configuration. This is notably the case for legacy crypto options from Mbed TLS 3.6, which for the most part are internal macros in TF-PSA-Crypto 1.0.
A configuration file may use removed options harmlessly if the configuration was intended to work with both the old and the new version of the library. Users who want to do that can make the definitions conditional on the library version (e.g. `#if defined(TF_PSA_CRYPTO_VERSION_MAJOR) && TF_PSA_CRYPTO_VERSION_MAJOR > 1`), so if we have a mechanism to forbid removed options, it is not particularly useful to allow users to bypass it.
Options that exist in Mbed TLS 3.6 and Mbed TLS 4.0 should not be considered removed from TF-PSA-Crypto 1.0, since it is perfectly legitimate to set them for the sake of Mbed TLS (see “[Subproject options](#subproject-options)”).
## Manually written checks
### Location of the manually written checks
Most manually configuration checks are located in <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>\_check\_config.h</code>.
This header is included by <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>_config.c</code>.
### Behavior of the manually written checks
The manually written checks run on the finalized configuration, i.e. at the end of `build_info.h`, after `*adjust*.h`.
The checks generally fit into a few patterns:
* If X is enabled then Y must be enabled because Y requires X to work. This was very common historically. Since Mbed TLS 3.0, we have gradually moved towards a more additive system, where enabling Y automatically enables its dependencies, but many cases of direct requirements still need to be specified manually.
* If X is enabled then one of Y1, Y2, Y3… must be enabled. We can't enable a Y automatically because we don't know which one.
* X and Y can't both be enabled.
### Configuration checks up to Mbed TLS 3.x
In Mbed TLS 2.x, there were manually written config checks in `<mbedtls/check_config.h>`. It was the job of `mbedtls/config.h` (which could be overridden by the user) to include that file. The configuration checks were thus performed whenever building a library source file or an application source file.
In Mbed TLS 3.x, there were manually written config checks in `<mbedtls/check_config.h>`. This header was systematically included by `<mbedtls/build_info.h>`. The configuration checks were thus performed whenever building a library source file or an application source file.
## Generated checks
### Location of the generated checks
The generated checks are located in
<code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>\_config\_check\_\*.h</code>.
These headers are included by <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>\_config.c</code>.
These are internal headers, included by one library file. This way, we run the config checks exactly once during a normal build.
### Behavior of the generated checks
The generated checks consist of three parts:
1. Some initial setup in `*_before.h`, to detect the situation before including the user's configuration file (but after the command line — this is unavoidable). This header is included before `build_info.h`.
2. The actual checks on the user configuration, in `*_after.h`. This header should also clean up by undefining some temporary macros. This header is included by `build_info.h` after reading the user's configuration files, but before defining derived macros in `*adjust*.h`. (This is not the normal behavior of `build_info.h`, it is done only if the file that includes `build_info.h` defines the macro <code><em>PROJECT\_NAME</em>\_INCLUDE\_AFTER\_RAW\_CONFIG</code>.)
3. Additional checks that can be performed on the final configuration. At the time of writing, all such checks are [written manually](#manually-written-checks), but the infrastructure is in place if we want to generate some.
### How the checks are generated
The checks are generated by `scripts/generate_config_checks.py` in each project. Each project contains a description of what do check. A Python module in the framework contains code to transform this description into the C header files.
The generation happens before build time as part of `make generated_files` or similar.
### Use of historical configuration information
The generated checks are based at least in part on historical information about what configuration options and derived macros existed in previous versions of the library. This historical information is stored in the [`history`](https://github.com/Mbed-TLS/mbedtls-framework/tree/main/history) directory of the framework repository. It can be created with [`scripts/save_config_history.sh`](https://github.com/Mbed-TLS/mbedtls-framework/blob/main/scripts/save_config_history.sh).
## Validation
Each project contains a script `tests/scripts/test_generate_config_checks.py` which is invoked by `all.sh`.
### Unit tests for code generation
The config check tests include some basic unit tests around the code generation, validating that certain configurations are accepted and that others are rejected with an assertion on the `#error` message.
### Checks for forbidden configurations
The config check tests can validate that certain configurations are forbidden.
The config check tests work by attempting to compile <code><em>LIBRARY\_DIRECTORY</em>/<em>PROJECT\_NAME</em>_config.c</code> which includes both [manually written checks](#manually-written-checks) and [generated checks](#generated-checks). Both preprocessor `#error` and `static_assert` can be detected.

View File

@@ -0,0 +1,138 @@
Version-independent build and test framework
============================================
## Introduction
The [`mbedtls-framework`](https://github.com/Mbed-TLS/mbedtls-framework) repository provides tooling used to build and test TF-PSA-Crypto (all versions) and Mbed TLS from 3.6.0 onwards.
## Requirements
### Initial motivation
Mbed TLS 3.x was a library for cryptography, X.509 and TLS. In 2024, the cryptography part of the library moved to a separate repository: [TF-PSA-Crypto](https://github.com/Mbed-TLS/TF-PSA-Crypto). Many support files are used by both projects: several helper scripts in `scripts` and `tests/scripts`, most of the test data in `tests/data`, a few helper programs under `programs`, most of the test helper code in `tests/include`, `tests/src` and `tests/drivers`, etc.
The Mbed TLS project maintains long-time support (LTS) branches (with only bug fixes) in addition to the `development` branch where new features are added. Fixes to bugs often need to be backported from `development` to LTS branches, which involves backporting tests, which often involves backporting test helper code. If we had a place to put files shared among multiple maintained branches, that would reduce the amount of backporting.
The `mbedtls-framework` was created to be a shared place for files that need to be shared by two or more of Mbed TLS 3.6 LTS, Mbed TLS 4.x development and TF-PSA-Crypto (as well as other LTS branches that will be created in the future). Mbed TLS 2.28 LTS was excluded from consideration due to its short remaining lifetime which would make any benefits small.
### Usage of the repository
The [`mbedtls-framework`](https://github.com/Mbed-TLS/mbedtls-framework) repository is consumed by each maintained branch of [Mbed TLS](https://github.com/Mbed-TLS/mbedtls) and [TF-PSA-Crypto](https://github.com/Mbed-TLS/TF-PSA-Crypto). This includes development branches, release branches and long-time support branches. (Exception: the older branch Mbed TLS 2.28 LTS was excluded.)
In each consuming branch, the `mbedtls-framework` repository appears as a Git submodule located at the path `/framework`.
### Requirements for the framework repository
#### Framework repository versioning
The framework repository is not versioned: projects are only supposed to consume the tip of the `main` branch. There are no tagged releases. However, each release of a consuming branch will designate a specific commit of the framework repository (this behavior is built into Git submodules), which can be tagged accordingly.
At any point in time, each consuming branch requires a specific commit in the framework repository. Moving a consuming branch to the tip of the framework repository is a manual action. As a consequence, breaking changes are possible: they will not break any actual commit, they would only prevent a consuming branch from updating its submodule version to the tip of the framework repository.
However, breaking changes are still problematic. Breaking changes in the framework repository require the affected consuming branches to fully adapt to the changes when they want to gain access to any new features in the framework repository. Breaking changes in a consuming branch that concern a feature that is consumed by the framework repository (e.g. internal library functions called by test helper functions) have the same effect.
To facilitate parallel development, major changes should avoid breaking existing code and should provide a transition period. For example, if a function needs a new argument, define a new function with a new name, start using the new fuction, and later remove the old function.
### Requirements for consuming repositories
We generalize some current principles:
* For development work and to run the CI, you need a Git checkout.
* To build the project and run functional tests, you need a complete set of files, but you don't need a Git checkout.
* To just build the library, if the platform-independent generated files are present, you only need the `include` directory and the directories containing library C files (`library`, `3rdparty`, `core`, `drivers` depending on the repository and desired features).
#### Requirements for development in consuming branches
Consuming branches must have the framework repository as a Git submodule for development work and CI scripts.
Compared with pre-framework tooling, this means that Git submodules must be enabled. This requires an explicit step in many Git APIs (e.g. running `git submodule update --init` after `git init`, or passing `--recurse-submodules` to `git checkout`).
#### Requirements for processes involving consuming branches
Release archives must include the content of the framework repository.
#### Requirements for tooling in consuming branches
Consuming branches may assume that the `framework` submodule is present wherever they assume a Git checkout.
Consuming branches may assume that the content of the `framework` directory is present anywhere where they would normally assume that all files are present. In particular, this allows the use of framework files for:
* Generating configuration-independent files (e.g. `make generated_files`), including the ones in the `library` directory.
* `make lib` (with GNU make or CMake) from a pristine checkout (because this involves `make generated_files`).
* `make test` (even if all the tests have been built).
Consuming branches must not assume that the framework is present when merely building the library. In particular:
* Our provided build scripts (e.g. `library/Makefile`, `library/CMakeLists.txt`) must not require any files from `framework` when compiling the library.
* It's ok to have a file in `library` with a make dependency on a framework file, as long as the build works when the framework file is missing. This allows `make lib` to work as long as the generated files are present.
* Library source files must not rely on headers from the framework.
#### Requirements for users of consuming branches
Corresponding to the requirements on the repository above:
* Contributors need the framework submodule.
* Users who wish to run full CI tests need the framework submodule.
* Users who want to build or run tests need the `framework` directory content.
* Users who merely want to build the library, and who have the configuration-independent files already generated, do not need the `framework` directory content.
## Contents of the framework repository
### Criteria for inclusion
In general, a file should be in the framework repository if it is expected to be present with near-identical content in two or more consuming branches. Some files have a significant proportion of shared content and branch-specific content; such files should be split into a shared part and a non-shared part.
For example:
* `test_suite_*.function` contains a lot of code that is specific to each consuming branch. Even when the same test function exists in all maintained branches, there are often minor differences such as a deprecated alternative that only exists in older branches, differences in compile-time dependencies, etc. Thus we do not expect to share these files. Common code can go into separate `.c` files, historically under `tests/src`, that are in the framework repository.
* `test_suite_*.data` contains many test cases that exist in all maintained branches. However the exact expression of these test cases are often different, for example due to compile-time dependencies. Furthermore the set of test cases is often different, for example due to cryptographic mechanisms that are added or removed. Thus we do not expect to share these files. Where there is a lot of commonality, the test cases can be generated from a script located in the framework repository, with code in the generation script to handle the differing parts.
## CI architecture
* CI in consuming repositories must support Git submodules. Other than that, keep the CI as it is now. In particular, the CI in consuming repositories does not need to consider anything but the commit that the framework submodule points to.
* CI in the framework repository should run a subset of the CI of all consuming branches, to warn about unintended breakage. This way, most of the time, updating the framework submodule in a consuming branch to the tip of the `main` branch should work. Gatekeepers can bypass this check if the incompatibility is deliberate.
* When merging a pull request to an official branch in a consuming repository (`development`, LTS branches), check that the framework submodule's commit is on the main branch of the `mbedtls-framework` submodule.
TODO: once this is set up, detail the processes here.
## How to make a change
### Change in a consuming branch requiring a new framework feature
If a change in a consuming branch requires a new feature in the framework, you need to make both a pull request in the framework repository and a pull request in the framework repository.
1. Make a pull request (PR) in the framework repository.
2. Upload the framework branch to the framework repository itself (not a fork). This is necessary for the commit to be available on the CI of the consuming repositories (and also for it to be conveniently available to reviewers).
Open question: can we make the CI work with a fork, and make using forks convenient enough for reviewers, so that people don't need to upload the branch to the main repository?
3. Make a pull request to the consuming branch. Include a commit that advances the submodule to the tip of the branch in the framework repository.
4. If there is rework in the framework PR that is needed for the consuming PR's review or CI, update the framework branch in the framework repository.
5. After the framework PR is merged, update the consuming PR to update the framework submodule to the merge commit (or a later commit).
### Backward-incompatible change in the framework repository
This section discusses cases where a change in the framework repository breaks one or more consuming branches. This includes cases where the change starts in a consuming branch, for example if some test helper code in the framework repository calls an internal library function which is removed or has its API changed.
#### Split approach for backward-incompatible framework changes
If a change in the framework repository breaks a consuming branch, it should ideally be split into two parts: one that adds the new feature, and one that removes the old feature. The new feature may be gated by a compilation directive if it's convenient to have only one of the versions at compile time.
1. Make and merge a pull request in the framework repository with a backward-compatible change.
2. Update all affected consuming branches to:
1. update the framework submodule to the new version;
2. migrate all uses of the old feature to the new feature.
3. Make and merge a pull request in the framework repository that removes the old version of the feature.
#### Watershed approach for backward-incompatible framework changes
If a change in the framework repository breaks a consuming branch, it is possible to make it in a single step in the framework repository. However, this makes it mandatory to reflect this change in consuming branches the next time their framework submodule is updated. Therefore this should only be done if the change can be reflected quickly and there are no other urgent pending framework-submodule updates.
1. Make a pull request (PR) in the framework repository with a backward-incompatible change.
2. For each affected consuming branch, make a PR that updates the framework submodule to the new version and changes the code to work with the updated framework code. Wait for those PR to be approved and passing the CI.
3. Merge the framework PR.
4. Update the PR in the consuming branches and merge them.
## Releases
Release archives for a consuming branch must include the content of the framework repository. (Note that as of Git 2.39, `git archive` does not support submodules, so it is insufficient to generate a release archive.)
The framework repository does not have releases of its own.