Skip to content

Commit 1910ad5

Browse files
infra: migrate chronos to helper.py (#14313)
``` $ python3 infra/helper.py check-tests --integrity-check json-c ... 23/25 Test #23: test_object_iterator ............. Passed 0.02 sec Start 24: test_json_pointer 24/25 Test #24: test_json_pointer ................ Passed 0.02 sec Start 25: test_json_patch 25/25 Test #25: test_json_patch .................. Passed 0.03 sec 100% tests passed, 0 tests failed out of 25 Total Test time (real) = 0.71 sec Integrity validator run tests for project: json-c Diff patching for stage after. Diff patch analysis begin. Stage: after, Current working dir: /src/json-c Diff patch analysis after stage. Git repo found: /src/json-c Diff patch generated at /tmp/chronos-diff.patch Difference between diffs: Patch result: success. No patch found that affects source control versioning. INFO:chronos.manager:succeeded patch: True INFO:chronos.manager:run_tests.sh result succeeded: does not patch source control INFO:chronos.manager:json-c test completion succeeded: Duration of run_tests.sh: 2.45 seconds ``` and for a failing project: ``` $ python3 infra/helper.py check-tests --integrity-check cups ... > -#~ msgstr "Utilização: cups-x509 [OPÇÕES] [COMANDO] [ARGUMENTO]" > - > -#, c-format > -#~ msgid "cups-x509: Bad URI '%s'." > -#~ msgstr "O URI '%s' não é válido para o cups-x509." > - > -#, c-format > -#~ msgid "cups-x509: Unable to connect to '%s' on port %d: %s" > -#~ msgstr "Não foi possível conectar '%s' na porta %d de %s para o cups-x509" Patch result: failed. Patch found that affects source control versioning. INFO:chronos.manager:succeeded patch: False INFO:chronos.manager:run_tests.sh result failed: patches source control INFO:chronos.manager:cups test completion failed: Duration of run_tests.sh: 278.28 seconds ``` Cups is failing because it patches the source control (fix in #14291). --------- Signed-off-by: David Korczynski <[email protected]>
1 parent 9158d8b commit 1910ad5

14 files changed

+762
-433
lines changed

infra/chronos/README.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Chronos: rebuilding OSS-Fuzz harnesses using cached builds
2+
3+
Chronos is a utility tooling to enable fast re-building of OSS-Fuzz projects
4+
and analysis of projects' testing infrastructure. This is used by projects,
5+
e.g. [OSS-Fuzz-gen](https://github.com/google/oss-fuzz-gen) to help speed up
6+
valuation processes during fuzzing harness generation.
7+
8+
At the core, Chronos relies on caching containers after project build, in order
9+
to enable fast rebuilding of a project following minor patches, and also enable
10+
running of the tests in a given project. To support this, Chronos creates a snapshot
11+
of the Docker container given project post build completion. This means that all `.o` files, generated
12+
configurations etc. persist in the Docker container. These artifacts are then
13+
leveraged for future "replay builds" where only a minor part of the project has changed,
14+
e.g. due to some patching on the project. This patching could be e.g. minor adjustments
15+
to the fuzzing harness source code e.g. by [oss-fuzz-gen](https://github.com/google/oss-fuzz-gen).
16+
17+
As such, at the core of Chronos are cached containers that are generated by taking a
18+
snapshot of the container of a project post project build.
19+
20+
Chronos is focused on two features, rebuilding projects fast and running the
21+
tests of a given project.
22+
23+
24+
## Chronos features: fast rebuilding and running the tests of a project
25+
26+
### CLI interface for Chronos
27+
28+
The default route to validating Chronos is using the CLI available in `infra/experimental/chronos/manager.py`
29+
30+
### Chronos feature: Fast rebuilding
31+
32+
Chronos enables rebuilding projects efficiently in contexts where only a small patch
33+
needs to be evaluated in the target. This is achieved by running a replay build script
34+
in the build container, similarly to how a regular `build_fuzzers` command would run, but
35+
with the caveat that the replay build script only performs a subset of the operations
36+
of the original `build.sh`.
37+
38+
The replay build scripts are constructed in two ways: manually or automatically.
39+
40+
#### Option 1: Automated rebuilds
41+
42+
Chronos supports automated rebuilding. This is meant as a generic mechanism to enable Chronos support for projects by default. This is achieved by:
43+
44+
1. Calling into a `replay_build.sh` script during the building inside the container [here](https://github.com/google/oss-fuzz/blob/206656447b213fb04901d15122692d8dd4d45312/infra/base-images/base-builder/compile#L292-L296)
45+
2. The `replay_build.sh` calls into `make_build_replayable.py`: [here](https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/replay_build.sh)
46+
3. `make_build_replayable.py` adjusts the build environment to wrap around common commands, to avoid performing a complete run of `build.sh`: [here](https://github.com/google/oss-fuzz/blob/master/infra/base-images/base-builder/make_build_replayable.py).
47+
48+
The automated rebuilding works in combination with [Ccache](https://ccache.dev/), in order to facilitate caching of e.g. `.o` files.
49+
This means that during rebuild mode as long as we have a cache, we don't need to e.g. run `configure` again and will only have to
50+
rebuild the changed source code.
51+
52+
#### Option 2: Manually provided replay builds
53+
54+
`replay_build.sh` above, is simply just a wrapper script around `build.sh` that aims to enable
55+
fast rebuilding of the project. This `replay_build.sh` can, however, be overwritten in the Dockerfile
56+
of the project's builder image to support a custom approach to fast rebuilding. Two examples of this is [php](https://github.com/google/oss-fuzz/blob/206656447b213fb04901d15122692d8dd4d45312/projects/php/replay_build.sh#L1) and [ffmpeg](https://github.com/google/oss-fuzz/blob/master/projects/ffmpeg/replay_build.sh#L1).
57+
58+
Providing a manual `replay_build.sh` is likely more efficient at build time and can help speed up the process. Automated replay build scripts can also be erroneous.
59+
60+
61+
#### Testing the validity of a replay build
62+
63+
The Chronos manager can use the `manager.py` to validate the validity of a
64+
replay build for a given project:
65+
66+
```sh
67+
python3 infra/experimental/chronos/manager.py check-replay tinyobjloader
68+
```
69+
70+
If the above command fails for the relevant project, then the replay build feature
71+
does not work for the given project.
72+
73+
### Chronos feature: Running tests of a project
74+
75+
The second part of Chronos is a feature to enable running the tests of a given
76+
project. This is done by way of a script `run_tests.sh`. Samples of
77+
this script include [jsonnet](https://github.com/google/oss-fuzz/blob/master/projects/jsonnet/run_tests.sh#L1) and [tinyobjloader](https://github.com/google/oss-fuzz/blob/master/projects/tinyobjloader/run_tests.sh#L1).
78+
79+
80+
#### Run tests constraints
81+
82+
1. The `run_tests.sh` main task is to run the tests of a project and return `0` upon success and non-null otherwise.
83+
2. The `run_tests.sh` script must leave the main repository in the state as it was prior to the execution of `run_tests.sh` relative to `git diff` (or similar diff features of other version control systems).
84+
85+
#### Testing the validity of run_tests.sh
86+
87+
The Chronos manager can use the `manager.py` to validate the validity of a
88+
`run_tests.sh` script:
89+
90+
```sh
91+
python3 infra/experimental/chronos/manager.py check-tests json-c
92+
```
93+
94+
95+
### Constraints imposed on replay_build.sh and run_tests.sh
96+
97+
At the core of chronos are the two scripts `replay_build.sh` and `run_tests.sh`. We have a default
98+
mechanism for `replay_build.sh` so it's not strictly necessary to have a custom one, although it will
99+
likely improve speed and maybe correctness by providing one.
100+
101+
There are three stages of the Chronos workflow:
102+
103+
1. The cached containers represent the state of a build container after a successful project build.
104+
2. The `replay_build.sh` is able to rebuild a given project from the state of a cached container.
105+
3. The `run_tests.sh` script is able to run the tests of a given project. This should be able to succeed following the running of a `replay_build.sh`.
106+
107+
The stages (2) and (3) must both support running without network connectivity.
108+
Specifically, this means that the `replay_build.sh` must not do tasks e.g. fetch
109+
dependencies, download corpus, or anything of this nature. Similarly, the `run_tests.sh`
110+
must be able to operate completely in a closed network environment.
111+
112+
113+
## Pre-built images.
114+
115+
Chronos cached images are built daily, and pre-built images are available at:
116+
117+
- `us-central1-docker.pkg.dev/oss-fuzz/oss-fuzz-gen/<PROJECT>-ofg-cached-address`
118+
- `us-central1-docker.pkg.dev/oss-fuzz/oss-fuzz-gen/<PROJECT>-ofg-cached-coverage`
119+
120+
They can be used as drop-in replacements for the usual `gcr.io/oss-fuzz/<PROJECT>` images.

infra/chronos/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
#!/bin/bash -eux
2+
# Copyright 2025 Google LLC.
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
#
16+
###############################################################################
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash -eux
2+
# Copyright 2025 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
echo "Starting prepare cache build script"
16+
export PATH=/ccache/bin:$PATH
17+
python3.11 -m pip install -r /chronos/requirements.txt
18+
rm -rf /out/*
19+
compile
20+
cp -n /usr/local/bin/replay_build.sh $SRC/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/bash -eux
2+
# Copyright 2025 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
chmod +x /src/run_tests.sh
17+
find /src/ -name "*.profraw" -exec rm -f {} \;
18+
/src/run_tests.sh
19+
python3 /chronos/coverage_test_collection.py
20+
chmod -R 755 /out/test-html-generation/
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash -eux
2+
# Copyright 2025 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
echo "Starting container patch replay script: $1"
17+
18+
python3 /chronos/integrity_validator_check_replay.py $1
19+
20+
export PATH=/ccache/bin$PATH
21+
rm -rf /out/*
22+
compile
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/bin/bash -eux
2+
# Copyright 2025 Google LLC
3+
#
4+
# Licensed under the Apache License, Version 2.0 (the "License");
5+
# you may not use this file except in compliance with the License.
6+
# You may obtain a copy of the License at
7+
#
8+
# http://www.apache.org/licenses/LICENSE-2.0
9+
#
10+
# Unless required by applicable law or agreed to in writing, software
11+
# distributed under the License is distributed on an "AS IS" BASIS,
12+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
# See the License for the specific language governing permissions and
14+
# limitations under the License.
15+
16+
echo "Starting container patch tests script"
17+
18+
# Ensure dependencies are installed
19+
python3 -m pip install -r /chronos/requirements.txt
20+
21+
# Capture patch, run tests and then diff patches.
22+
python3 /chronos/integrity_validator_run_tests.py diff-patch before
23+
chmod +x /src/run_tests.sh
24+
/src/run_tests.sh
25+
python3 /chronos/integrity_validator_run_tests.py diff-patch after
File renamed without changes.

infra/experimental/chronos/integrity_validator_check_replay.py renamed to infra/chronos/integrity_validator_check_replay.py

File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)