chore(opencode): fix drifted agent/skill docs and repo hygiene #283
@@ -8,3 +8,7 @@ build-*/
|
|||||||
build2/
|
build2/
|
||||||
build3/
|
build3/
|
||||||
build_docker2/
|
build_docker2/
|
||||||
|
|
||||||
|
# Test/run artifacts
|
||||||
|
root/
|
||||||
|
test_partial_install_tmp/
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ Do not wait for the user to tell you CI failed — check proactively. The user s
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -27,16 +27,19 @@ FetchContent_Declare(xxhash GIT_REPOSITORY https://github.com/Cyan4973/xxHash GI
|
|||||||
FetchContent_MakeAvailable(xxhash)
|
FetchContent_MakeAvailable(xxhash)
|
||||||
|
|
||||||
# Sanitizer option
|
# Sanitizer option
|
||||||
set(SANITIZER "none" CACHE STRING "Sanitizer to enable (address, thread, none)")
|
set(SANITIZER "none" CACHE STRING "Sanitizer to enable (address, thread, undefined, none)")
|
||||||
set_property(CACHE SANITIZER PROPERTY STRINGS address thread none)
|
set_property(CACHE SANITIZER PROPERTY STRINGS address thread undefined none)
|
||||||
if(SANITIZER STREQUAL "address")
|
if(SANITIZER STREQUAL "address")
|
||||||
add_compile_options(-fsanitize=address -fno-omit-frame-pointer -g)
|
add_compile_options(-fsanitize=address -fno-omit-frame-pointer -g)
|
||||||
add_link_options(-fsanitize=address)
|
add_link_options(-fsanitize=address)
|
||||||
elseif(SANITIZER STREQUAL "thread")
|
elseif(SANITIZER STREQUAL "thread")
|
||||||
add_compile_options(-fsanitize=thread -fno-omit-frame-pointer -g)
|
add_compile_options(-fsanitize=thread -fno-omit-frame-pointer -g)
|
||||||
add_link_options(-fsanitize=thread)
|
add_link_options(-fsanitize=thread)
|
||||||
|
elseif(SANITIZER STREQUAL "undefined")
|
||||||
|
add_compile_options(-fsanitize=undefined -fno-omit-frame-pointer -g)
|
||||||
|
add_link_options(-fsanitize=undefined)
|
||||||
elseif(NOT SANITIZER STREQUAL "none")
|
elseif(NOT SANITIZER STREQUAL "none")
|
||||||
message(FATAL_ERROR "Unknown sanitizer: ${SANITIZER}. Supported values: address, thread, none")
|
message(FATAL_ERROR "Unknown sanitizer: ${SANITIZER}. Supported values: address, thread, undefined, none")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(STRICT_WARNINGS "Enable strict warnings" OFF)
|
option(STRICT_WARNINGS "Enable strict warnings" OFF)
|
||||||
@@ -84,7 +87,7 @@ tests/integration/ — Python pytest integration tests
|
|||||||
### Dependencies
|
### Dependencies
|
||||||
- **zstd** — found via `find_library(ZSTD_LIBRARY zstd)`
|
- **zstd** — found via `find_library(ZSTD_LIBRARY zstd)`
|
||||||
- **OpenSSL** — found via `find_package(OpenSSL REQUIRED)` (TLS 1.2+ transport)
|
- **OpenSSL** — found via `find_package(OpenSSL REQUIRED)` (TLS 1.2+ transport)
|
||||||
- **xxHash** — fetched via `FetchContent` from GitHub (delta transfer hashing, v0.8.3)
|
- **xxHash** — fetched via `FetchContent` from the upstream repository (delta transfer hashing, v0.8.3)
|
||||||
- **pthreads** — found via `find_package(Threads REQUIRED)`
|
- **pthreads** — found via `find_package(Threads REQUIRED)`
|
||||||
- **C11 standard** — required
|
- **C11 standard** — required
|
||||||
- **CMake 3.22+** — minimum version
|
- **CMake 3.22+** — minimum version
|
||||||
@@ -94,7 +97,7 @@ tests/integration/ — Python pytest integration tests
|
|||||||
- Use `file(GLOB ...)` for source collection (existing pattern).
|
- Use `file(GLOB ...)` for source collection (existing pattern).
|
||||||
- All targets link `Threads::Threads`, `${ZSTD_LIBRARY}`, `OpenSSL::SSL`, `OpenSSL::Crypto`, and `xxhash`.
|
- All targets link `Threads::Threads`, `${ZSTD_LIBRARY}`, `OpenSSL::SSL`, `OpenSSL::Crypto`, and `xxhash`.
|
||||||
- Include directories: `src/shared`, `src/server`, `src/client`, `tests` (for test target).
|
- Include directories: `src/shared`, `src/server`, `src/client`, `tests` (for test target).
|
||||||
- Sanitizer support: pass `-DSANITIZER=address` or `-DSANITIZER=thread` to cmake (live option in CMakeLists.txt).
|
- Sanitizer support: pass `-DSANITIZER=address`, `-DSANITIZER=thread`, or `-DSANITIZER=undefined` to cmake (live option in CMakeLists.txt).
|
||||||
- Build with `cmake -B build -S . && cmake --build build -j$(nproc)`.
|
- Build with `cmake -B build -S . && cmake --build build -j$(nproc)`.
|
||||||
- For CI, dependencies are provided by the project's custom Docker image (repo-root `Dockerfile`, same image CI uses). For local development, use `nix-shell`. Never add `apt-get install` / `pip install` to CI workflows. See `AGENTS.md`.
|
- For CI, dependencies are provided by the project's custom Docker image (repo-root `Dockerfile`, same image CI uses). For local development, use `nix-shell`. Never add `apt-get install` / `pip install` to CI workflows. See `AGENTS.md`.
|
||||||
|
|
||||||
@@ -105,7 +108,7 @@ tests/integration/ — Python pytest integration tests
|
|||||||
3. Add new dependencies with `find_package` or `find_library`.
|
3. Add new dependencies with `find_package` or `find_library`.
|
||||||
4. When adding a new executable target, follow the pattern of existing targets.
|
4. When adding a new executable target, follow the pattern of existing targets.
|
||||||
5. When adding a new library (static/shared), use `add_library` and follow the project's naming.
|
5. When adding a new library (static/shared), use `add_library` and follow the project's naming.
|
||||||
6. For sanitizer builds, pass `-DSANITIZER=address` or `-DSANITIZER=thread` to cmake (matching CI's matrix strategy).
|
6. For sanitizer builds, pass `-DSANITIZER=address`, `-DSANITIZER=thread`, or `-DSANITIZER=undefined` to cmake (matching CI's matrix strategy).
|
||||||
7. Always verify the build compiles after changes.
|
7. Always verify the build compiles after changes.
|
||||||
|
|
||||||
## Sanitizer Configurations
|
## Sanitizer Configurations
|
||||||
@@ -119,11 +122,9 @@ cmake -B build -S . -DSANITIZER=thread # ThreadSanitizer (race conditions)
|
|||||||
cmake --build build -j$(nproc)
|
cmake --build build -j$(nproc)
|
||||||
```
|
```
|
||||||
|
|
||||||
For UndefinedBehaviorSanitizer (no `-DSANITIZER=undefined` option in CMakeLists.txt yet), use the manual flag approach:
|
UndefinedBehaviorSanitizer uses the same built-in option:
|
||||||
```bash
|
```bash
|
||||||
cmake -B build -S . \
|
cmake -B build -S . -DSANITIZER=undefined
|
||||||
-DCMAKE_C_FLAGS="-fsanitize=undefined -fno-omit-frame-pointer -g" \
|
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=undefined"
|
|
||||||
cmake --build build -j$(nproc)
|
cmake --build build -j$(nproc)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -159,7 +160,7 @@ cmake -B build -S . -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
|||||||
```bash
|
```bash
|
||||||
cmake -B build -S .
|
cmake -B build -S .
|
||||||
cmake --build build -j$(nproc)
|
cmake --build build -j$(nproc)
|
||||||
./build/server
|
./build/server -p 8080 --allow-unauthenticated
|
||||||
./build/client
|
./build/client
|
||||||
./build/tests
|
./build/tests
|
||||||
```
|
```
|
||||||
@@ -187,7 +188,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ FastSync is a file synchronization tool (like rsync, but faster). It transfers f
|
|||||||
cmake -B build -S . && cmake --build build -j$(nproc)
|
cmake -B build -S . && cmake --build build -j$(nproc)
|
||||||
|
|
||||||
# Server (TCP mode)
|
# Server (TCP mode)
|
||||||
./build/server
|
./build/server -p 8080 --allow-unauthenticated
|
||||||
|
|
||||||
# Client (TCP mode)
|
# Client (TCP mode)
|
||||||
./build/client --source-dir /path/to/send --dest-dir /path/to/receive --save-to-disk
|
./build/client --source-dir /path/to/send --dest-dir /path/to/receive --save-to-disk
|
||||||
@@ -37,13 +37,13 @@ cmake -B build -S . && cmake --build build -j$(nproc)
|
|||||||
|
|
||||||
# Run tests
|
# Run tests
|
||||||
./build/tests # unit tests
|
./build/tests # unit tests
|
||||||
python3 test.py # integration tests
|
python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv" # integration tests
|
||||||
```
|
```
|
||||||
|
|
||||||
## Code Walkthrough
|
## Code Walkthrough
|
||||||
|
|
||||||
### Client Entry Point (`src/client/client_cli.c`)
|
### Client Entry Point (`src/client/client_cli.c`)
|
||||||
- Parses CLI arguments using `getopt_long`
|
- Parses CLI arguments using a custom option-table parser (`OPTION_TABLE` in `src/client/client_cli.c`); there is no `getopt*` usage
|
||||||
- Creates `Config` struct with all options
|
- Creates `Config` struct with all options
|
||||||
- Detects SSH destinations (contains `:`)
|
- Detects SSH destinations (contains `:`)
|
||||||
- Calls into `client_send.c` for the actual transfer
|
- Calls into `client_send.c` for the actual transfer
|
||||||
@@ -109,7 +109,7 @@ Collection of files for batch transfer. Serialized with file count, then per-fil
|
|||||||
zstd streaming compression via `ZSTD_compressStream2`/`ZSTD_decompressStream`. Compression happens per-chunk in the sender stage. Level 1-22 (default 5). Streaming means memory usage stays bounded regardless of file size.
|
zstd streaming compression via `ZSTD_compressStream2`/`ZSTD_decompressStream`. Compression happens per-chunk in the sender stage. Level 1-22 (default 5). Streaming means memory usage stays bounded regardless of file size.
|
||||||
|
|
||||||
### "How does sendfile() work?"
|
### "How does sendfile() work?"
|
||||||
On Linux, `sendfile()` copies data directly from kernel file buffer to socket, bypassing userspace. ~2x faster for large files. Enabled with `-f` flag. Only works with TCP (not SSH, not compression).
|
On Linux, `sendfile()` copies data directly from kernel file buffer to socket, bypassing userspace. ~2x faster for large files. Enabled with `--sendfile` (long form only). Only works with TCP (not SSH, not compression).
|
||||||
|
|
||||||
### "How does incremental sync work?"
|
### "How does incremental sync work?"
|
||||||
Client sends file metadata (path, size, mtime) to server. Server checks if destination file has same size+mtime. If match, server responds `STATUS_OK` (skip). If mismatch, server responds `STATUS_NEXT` (send).
|
Client sends file metadata (path, size, mtime) to server. Server checks if destination file has same size+mtime. If match, server responds `STATUS_OK` (skip). If mismatch, server responds `STATUS_NEXT` (send).
|
||||||
@@ -138,7 +138,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -316,7 +316,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -14,10 +14,9 @@ Diagnose crashes, memory errors, hangs, and logic bugs. You use structured debug
|
|||||||
### Memory Errors
|
### Memory Errors
|
||||||
```bash
|
```bash
|
||||||
# AddressSanitizer (fast, recommended first)
|
# AddressSanitizer (fast, recommended first)
|
||||||
cmake -B build -S . -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
|
cmake -B build-asan -S . -DSANITIZER=address
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
|
cmake --build build-asan -j$(nproc)
|
||||||
cmake --build build -j$(nproc)
|
./build-asan/client # or ./build-asan/server -p 8080 --allow-unauthenticated
|
||||||
./build/client # or ./build/server
|
|
||||||
|
|
||||||
# Valgrind (slower, more thorough)
|
# Valgrind (slower, more thorough)
|
||||||
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes \
|
||||||
@@ -32,10 +31,9 @@ valgrind --tool=drd ./build/client ...
|
|||||||
|
|
||||||
### Thread Sanitizer
|
### Thread Sanitizer
|
||||||
```bash
|
```bash
|
||||||
cmake -B build -S . -DCMAKE_C_FLAGS="-fsanitize=thread" \
|
cmake -B build-tsan -S . -DSANITIZER=thread
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread"
|
cmake --build build-tsan -j$(nproc)
|
||||||
cmake --build build -j$(nproc)
|
./build-tsan/tests
|
||||||
./build/tests
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### GDB
|
### GDB
|
||||||
@@ -143,7 +141,7 @@ gprof ./build/client gmon.out
|
|||||||
|
|
||||||
### Step 5: Verify
|
### Step 5: Verify
|
||||||
- Run `./build/tests` (unit tests)
|
- Run `./build/tests` (unit tests)
|
||||||
- Run `python3 test.py` (integration tests)
|
- Run `python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"` (integration tests)
|
||||||
- Run under valgrind again to confirm clean
|
- Run under valgrind again to confirm clean
|
||||||
- Test under ASan again
|
- Test under ASan again
|
||||||
|
|
||||||
@@ -162,7 +160,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -16,12 +16,18 @@ Scan the codebase for patterns that suggest new feature opportunities. You ident
|
|||||||
### Module Map
|
### Module Map
|
||||||
```
|
```
|
||||||
src/client/ Client-side: CLI parsing, scanning, sending
|
src/client/ Client-side: CLI parsing, scanning, sending
|
||||||
client_cli.c Entry point, argument parsing, config setup
|
client_cli.c Entry point, OPTION_TABLE parser, config setup
|
||||||
|
usage.c Usage/help text (authoritative CLI flag list)
|
||||||
client_send.c Transfer orchestration, pipeline management
|
client_send.c Transfer orchestration, pipeline management
|
||||||
|
client_validation.c Destination/CLI validation
|
||||||
scanner.c BFS directory traversal, chunk building
|
scanner.c BFS directory traversal, chunk building
|
||||||
|
change_list.c File change-list bookkeeping
|
||||||
|
|
||||||
src/server/ Server-side: listening, receiving, writing
|
src/server/ Server-side: listening, receiving, writing
|
||||||
server.c TCP accept loop, per-connection handling
|
server.c TCP accept loop, per-connection handling
|
||||||
|
server_cli.c Server option-table CLI parsing
|
||||||
|
receiver.c Receiver-side file handling
|
||||||
|
receiver_pipeline.c Receiver worker pipeline
|
||||||
|
|
||||||
src/shared/ Shared libraries (used by both client and server)
|
src/shared/ Shared libraries (used by both client and server)
|
||||||
protocol.c/h Wire protocol: status codes, send/receive primitives
|
protocol.c/h Wire protocol: status codes, send/receive primitives
|
||||||
@@ -32,40 +38,63 @@ src/shared/ Shared libraries (used by both client and server)
|
|||||||
data.c/h Generic buffer type (Data)
|
data.c/h Generic buffer type (Data)
|
||||||
metadata.c/h File metadata (mode, uid, gid, mtime)
|
metadata.c/h File metadata (mode, uid, gid, mtime)
|
||||||
file.c/h File representation
|
file.c/h File representation
|
||||||
|
file_send.c/h Sender-side file transfer
|
||||||
|
file_receive.c/h Receiver-side file transfer
|
||||||
|
file_list.c/h File list model
|
||||||
|
file_store.c/h Destination file store
|
||||||
array_list.c/h Dynamic array
|
array_list.c/h Dynamic array
|
||||||
|
delta.c/h Delta transfer algorithm
|
||||||
|
checksum.c/h Whole-file/block checksums (xxHash, md5)
|
||||||
|
filter.c/h rsync-style filter rules
|
||||||
|
batch.c/h Batch files (--write-batch/--read-batch)
|
||||||
|
charset.c/h Filename charset conversion (--iconv)
|
||||||
|
chmod.c/h Permission modification (--chmod)
|
||||||
|
xattr.c/h Extended attributes
|
||||||
|
hardlink.c/h Hard-link handling
|
||||||
|
identity.c/h uid/gid mapping (--usermap/--groupmap/--chown)
|
||||||
|
credentials.c/h Daemon credentials
|
||||||
|
daemon_conf.c/h Daemon module configuration
|
||||||
|
motd.c/h Daemon MOTD
|
||||||
|
delay_updates.c/h Delayed update staging
|
||||||
|
stop_condition.c/h Stop-after/stop-at handling
|
||||||
transport_tcp.c/h TCP client/server with sendfile() zero-copy
|
transport_tcp.c/h TCP client/server with sendfile() zero-copy
|
||||||
transport_ssh.c/h SSH transport with ControlMaster
|
transport_ssh.c/h SSH transport with ControlMaster
|
||||||
transport_tls.c/h TLS encryption via OpenSSL
|
transport_tls.c/h TLS encryption via OpenSSL
|
||||||
multiprocessing.c/h Fork-based concurrency
|
multiprocessing.c/h Fork-based concurrency
|
||||||
log.c/h Logging utilities
|
log.c/h Logging utilities
|
||||||
utils.c/h Shared utilities
|
utils.c/h Shared utilities
|
||||||
|
file_types.h Shared file type definitions
|
||||||
```
|
```
|
||||||
|
|
||||||
### Existing CLI Flags (from client_cli.c)
|
### Existing CLI Flags (authoritative source: `src/client/usage.c`)
|
||||||
```
|
```
|
||||||
--source-dir <dir> Source directory to sync (required)
|
--source-dir <dir> Source directory
|
||||||
--dest-dir <dir> Destination directory on server (required)
|
--dest-dir <dir> Destination directory on server
|
||||||
--host <host> Server hostname/IP (required)
|
--server-host <ip> Server IP address (default: 127.0.0.1)
|
||||||
--port <port> Server TCP port
|
--server-port <n> Server port (default: 8080); --port is an alias
|
||||||
--server-mode Listen as server
|
-c, --checksum Verify content by checksum instead of size+mtime
|
||||||
--use-compression, -c Enable zstd compression
|
-z, --compress [level] Enable compression (level 1-22, default 5)
|
||||||
--use-multithreading, -m Enable multithreaded transfer
|
-j, --threads[=N] Enable multithreaded scanner/loader/sender pipeline
|
||||||
--use-sendfile, -s Use sendfile() zero-copy TCP
|
--chunk-serialization Enable chunk serialization (long form only)
|
||||||
--use-ssh, -S Use SSH transport
|
--sendfile sendfile() zero-copy (TCP only; long form only)
|
||||||
--use-tls, -T Enable TLS encryption
|
-s, --secluded-args Protect-args compatibility option (no effect)
|
||||||
--cert <file> TLS certificate file
|
--tls Enable TLS encryption; --cert/--key/--ca give PEMs
|
||||||
--key <file> TLS key file
|
--bwlimit <KB/s> Bandwidth limit in kilobytes per second
|
||||||
--ca <file> TLS CA certificate file
|
--delete Delete files on receiver not in source
|
||||||
--insecure Skip TLS verification
|
--incremental Skip files unchanged since last transfer
|
||||||
--bwlimit <bytes/s> Bandwidth limit
|
--delta Delta transfer for changed files (needs --incremental)
|
||||||
--delete Delete files not in source
|
-f, --filter=RULE rsync-style filter rule (+/- include/exclude)
|
||||||
--include <pattern> Include filter pattern
|
--exclude <pattern> Exclude files matching pattern
|
||||||
--exclude <pattern> Exclude filter pattern
|
--include <pattern> Only include files matching pattern
|
||||||
--dry-run Print what would be transferred
|
-m, --prune-empty-dirs Do not transfer empty directory entries
|
||||||
--save-to-disk Save transferred files to disk (for server tests)
|
-n, --dry-run Show what would be transferred
|
||||||
|
--save-to-disk Write received files to disk
|
||||||
--version Print version and exit
|
--version Print version and exit
|
||||||
--help Print help
|
--help Show help
|
||||||
```
|
```
|
||||||
|
> Always confirm the current flags with `./build/client --help`; the table above
|
||||||
|
> is a representative subset. `src/client/usage.c` is the authoritative list and
|
||||||
|
> `OPTION_TABLE` in `src/client/client_cli.c` is the parser (there is no `getopt*`).
|
||||||
|
|
||||||
## Feature Scout Checklist
|
## Feature Scout Checklist
|
||||||
|
|
||||||
@@ -288,7 +317,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ Design integration tests that verify the full transfer pipeline works end-to-end
|
|||||||
- Multiple configurations (TCP, SSH, TLS, compression, multithreading)
|
- Multiple configurations (TCP, SSH, TLS, compression, multithreading)
|
||||||
- Network shaping (LAN, WAN profiles)
|
- Network shaping (LAN, WAN profiles)
|
||||||
- Feature tests (dry run, archive, exclude, delete, incremental, bandwidth limit)
|
- Feature tests (dry run, archive, exclude, delete, incremental, bandwidth limit)
|
||||||
- Run: `python3 -m pytest tests/ -v --tb=short`
|
- Run: `python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"`
|
||||||
|
|
||||||
### 3. New: Focused Integration Tests
|
### 3. New: Focused Integration Tests
|
||||||
When adding new features or fixing bugs, write targeted integration tests.
|
When adding new features or fixing bugs, write targeted integration tests.
|
||||||
@@ -35,13 +35,14 @@ mkdir -p /tmp/fastsync_test/src
|
|||||||
echo "test content" > /tmp/fastsync_test/src/file.txt
|
echo "test content" > /tmp/fastsync_test/src/file.txt
|
||||||
|
|
||||||
# Start server
|
# Start server
|
||||||
./build/server &
|
./build/server -p 8080 --allow-unauthenticated &
|
||||||
SERVER_PID=$!
|
SERVER_PID=$!
|
||||||
sleep 0.5
|
sleep 0.5
|
||||||
|
|
||||||
# Run client
|
# Run client
|
||||||
./build/client --source-dir /tmp/fastsync_test/src \
|
./build/client --source-dir /tmp/fastsync_test/src \
|
||||||
--dest-dir /tmp/fastsync_test/dst \
|
--dest-dir /tmp/fastsync_test/dst \
|
||||||
|
--server-port 8080 \
|
||||||
--save-to-disk
|
--save-to-disk
|
||||||
|
|
||||||
# Verify
|
# Verify
|
||||||
@@ -76,7 +77,7 @@ openssl req -x509 -newkey rsa:2048 -keyout /tmp/key.pem -out /tmp/cert.pem \
|
|||||||
### Pattern 4: Incremental Sync
|
### Pattern 4: Incremental Sync
|
||||||
```bash
|
```bash
|
||||||
# First sync
|
# First sync
|
||||||
./build/client --source-dir /tmp/src --dest-dir /tmp/dst --save-to-disk -M
|
./build/client --source-dir /tmp/src --dest-dir /tmp/dst --save-to-disk
|
||||||
|
|
||||||
# Modify source
|
# Modify source
|
||||||
echo "updated" >> /tmp/src/file.txt
|
echo "updated" >> /tmp/src/file.txt
|
||||||
@@ -89,14 +90,14 @@ echo "updated" >> /tmp/src/file.txt
|
|||||||
### Pattern 5: Delete Verification
|
### Pattern 5: Delete Verification
|
||||||
```bash
|
```bash
|
||||||
# Initial sync
|
# Initial sync
|
||||||
./build/client --source-dir /tmp/src --dest-dir /tmp/dst --save-to-disk -M
|
./build/client --source-dir /tmp/src --dest-dir /tmp/dst --save-to-disk
|
||||||
|
|
||||||
# Add extra file to dest
|
# Add extra file to dest
|
||||||
echo "extra" > /tmp/dst/.../extra.txt
|
echo "extra" > /tmp/dst/.../extra.txt
|
||||||
|
|
||||||
# Sync with --delete
|
# Sync with --delete
|
||||||
./build/client --source-dir /tmp/src --dest-dir /tmp/dst \
|
./build/client --source-dir /tmp/src --dest-dir /tmp/dst \
|
||||||
--save-to-disk --delete -M
|
--save-to-disk --delete
|
||||||
|
|
||||||
# Verify extra.txt is gone
|
# Verify extra.txt is gone
|
||||||
test ! -f /tmp/dst/.../extra.txt
|
test ! -f /tmp/dst/.../extra.txt
|
||||||
@@ -115,7 +116,7 @@ The project uses Gitea Actions. Key jobs:
|
|||||||
jobs:
|
jobs:
|
||||||
new-job:
|
new-job:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
container: gitea.tap-tap.win/taptap/fastsync-ci:v7
|
container: gitea.tap-tap.win/taptap/fastsync-ci:v10
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Configure
|
- name: Configure
|
||||||
@@ -127,7 +128,7 @@ jobs:
|
|||||||
- name: Unit Tests
|
- name: Unit Tests
|
||||||
run: ./build-${{ matrix.sanitizer }}/tests
|
run: ./build-${{ matrix.sanitizer }}/tests
|
||||||
- name: Integration Tests
|
- name: Integration Tests
|
||||||
run: LSAN_OPTIONS=suppressions=.lsan-suppressions.txt python3 -m pytest tests/ -v --tb=short
|
run: LSAN_OPTIONS=suppressions=.lsan-suppressions.txt python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"
|
||||||
```
|
```
|
||||||
The symlink step is required because `tests/conftest.py` expects `./build` to exist.
|
The symlink step is required because `tests/conftest.py` expects `./build` to exist.
|
||||||
|
|
||||||
@@ -135,7 +136,7 @@ The symlink step is required because `tests/conftest.py` expects `./build` to ex
|
|||||||
|
|
||||||
After any code change:
|
After any code change:
|
||||||
- [ ] Unit tests pass: `./build/tests`
|
- [ ] Unit tests pass: `./build/tests`
|
||||||
- [ ] Integration tests pass: `python3 -m pytest tests/ -v --tb=short`
|
- [ ] Integration tests pass: `python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"`
|
||||||
- [ ] Build clean: no warnings with `-Wall`
|
- [ ] Build clean: no warnings with `-Wall`
|
||||||
- [ ] No memory errors: ASan clean
|
- [ ] No memory errors: ASan clean
|
||||||
- [ ] No thread errors: TSan clean (if threading involved)
|
- [ ] No thread errors: TSan clean (if threading involved)
|
||||||
@@ -156,7 +157,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
---
|
---
|
||||||
description: Top-level orchestrator that analyzes the FastSync codebase by delegating to specialized sub-agents and creates GitHub issues from their findings.
|
description: Top-level orchestrator that analyzes the FastSync codebase by delegating to specialized sub-agents and creates Gitea issues from their findings.
|
||||||
mode: subagent
|
mode: subagent
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -12,7 +12,7 @@ You are the primary orchestrator agent. Your job is to:
|
|||||||
2. Decide which specialized sub-agents to dispatch for analysis
|
2. Decide which specialized sub-agents to dispatch for analysis
|
||||||
3. Delegate analysis work using the task tool
|
3. Delegate analysis work using the task tool
|
||||||
4. Receive structured findings from sub-agents
|
4. Receive structured findings from sub-agents
|
||||||
5. Create GitHub issues from those findings using `gh issue create`
|
5. Create Gitea issues from those findings using `tea issues create`
|
||||||
6. Coordinate the overall analysis workflow end-to-end
|
6. Coordinate the overall analysis workflow end-to-end
|
||||||
|
|
||||||
> **Environment rule:** for CI, dependency installation must use the project's custom Docker image (repo-root `Dockerfile`, same as CI). For local development, use `nix-shell` (see `README.md`). See `AGENTS.md`.
|
> **Environment rule:** for CI, dependency installation must use the project's custom Docker image (repo-root `Dockerfile`, same as CI). For local development, use `nix-shell` (see `README.md`). See `AGENTS.md`.
|
||||||
@@ -97,7 +97,7 @@ First, read the repository structure to understand what exists:
|
|||||||
### Phase 2: Determine Analysis Scope
|
### Phase 2: Determine Analysis Scope
|
||||||
Based on what the user requests or what needs attention:
|
Based on what the user requests or what needs attention:
|
||||||
- **New features wanted?** → Dispatch `feature-scout` sub-agent
|
- **New features wanted?** → Dispatch `feature-scout` sub-agent
|
||||||
- **Security audit needed?** → Dispatch `security-screener` sub-agent
|
- **Security audit needed?** → Dispatch `security-auditor` sub-agent
|
||||||
- **Code quality review?** → Dispatch `code-quality-guardian` sub-agent
|
- **Code quality review?** → Dispatch `code-quality-guardian` sub-agent
|
||||||
- **All of the above?** → Run all three in parallel
|
- **All of the above?** → Run all three in parallel
|
||||||
|
|
||||||
@@ -110,7 +110,7 @@ Context: <provide summary of what was found in Phase 1>
|
|||||||
```
|
```
|
||||||
|
|
||||||
```
|
```
|
||||||
Task: Ask the security-screener agent to analyze the codebase.
|
Task: Ask the security-auditor agent to analyze the codebase.
|
||||||
Context: <provide summary of what was found in Phase 1>
|
Context: <provide summary of what was found in Phase 1>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -138,14 +138,14 @@ Each sub-agent returns findings in this structured format:
|
|||||||
- **Labels**: comma-separated labels for the issue
|
- **Labels**: comma-separated labels for the issue
|
||||||
```
|
```
|
||||||
|
|
||||||
### Phase 5: Create GitHub Issues
|
### Phase 5: Create Gitea Issues
|
||||||
For each finding, create a GitHub issue:
|
For each finding, create a Gitea issue:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gh issue create \
|
tea issues create --repo TapTap/FastSync \
|
||||||
--title "<Finding Title>" \
|
--title "<Finding Title>" \
|
||||||
--label "<labels>" \
|
--labels "<labels>" \
|
||||||
--body "## Description
|
--description "## Description
|
||||||
<description>
|
<description>
|
||||||
|
|
||||||
## Location
|
## Location
|
||||||
@@ -175,11 +175,13 @@ _This issue was automatically generated by the issue-creator agent._"
|
|||||||
|
|
||||||
### Duplicate Detection
|
### Duplicate Detection
|
||||||
Before creating an issue:
|
Before creating an issue:
|
||||||
1. Check existing open issues: `gh issue list --state open --label "<label>"`
|
1. Check existing open issues: `tea issues list --repo TapTap/FastSync --state open --labels "<label>"`
|
||||||
2. Search for similar titles using `gh issue list --search "<keywords>"`
|
2. Search for similar titles using `tea issues list --repo TapTap/FastSync --keyword "<keywords>"`
|
||||||
3. If a similar issue exists, add a comment instead of creating a duplicate:
|
3. If a similar issue exists, add a comment instead of creating a duplicate:
|
||||||
```bash
|
```bash
|
||||||
gh issue comment <issue-number> --body "Additional finding from automated analysis: <details>"
|
tea comment --repo TapTap/FastSync <issue-number> "Additional finding from automated analysis: <details>"
|
||||||
|
# or POST to the Gitea API:
|
||||||
|
# POST https://gitea.tap-tap.win/api/v1/repos/TapTap/FastSync/issues/<n>/comments
|
||||||
```
|
```
|
||||||
|
|
||||||
## Sub-Agent Reference
|
## Sub-Agent Reference
|
||||||
@@ -189,13 +191,12 @@ Before creating an issue:
|
|||||||
| Agent | File | Purpose |
|
| Agent | File | Purpose |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| feature-scout | `.opencode/agents/feature-scout.md` | Scans for feature opportunities |
|
| feature-scout | `.opencode/agents/feature-scout.md` | Scans for feature opportunities |
|
||||||
| security-screener | `.opencode/agents/security-screener.md` | Scans for security vulnerabilities |
|
| security-auditor | `.opencode/agents/security-auditor.md` | Security audits and vulnerability scans |
|
||||||
| code-quality-guardian | `.opencode/agents/code-quality-guardian.md` | Scans for code quality improvements |
|
| code-quality-guardian | `.opencode/agents/code-quality-guardian.md` | Scans for code quality improvements |
|
||||||
| architect | `.opencode/agents/architect.md` | Architecture reviews |
|
| architect | `.opencode/agents/architect.md` | Architecture reviews |
|
||||||
| c-reviewer | `.opencode/agents/c-reviewer.md` | C code correctness reviews |
|
| c-reviewer | `.opencode/agents/c-reviewer.md` | C code correctness reviews |
|
||||||
| debugger | `.opencode/agents/debugger.md` | Bug diagnosis |
|
| debugger | `.opencode/agents/debugger.md` | Bug diagnosis |
|
||||||
| refactorer | `.opencode/agents/refactorer.md` | Code refactoring |
|
| refactorer | `.opencode/agents/refactorer.md` | Code refactoring |
|
||||||
| security-auditor | `.opencode/agents/security-auditor.md` | Security audits |
|
|
||||||
| test-writer | `.opencode/agents/test-writer.md` | Test development |
|
| test-writer | `.opencode/agents/test-writer.md` | Test development |
|
||||||
| perf-analyst | `.opencode/agents/perf-analyst.md` | Performance analysis |
|
| perf-analyst | `.opencode/agents/perf-analyst.md` | Performance analysis |
|
||||||
| protocol-designer | `.opencode/agents/protocol-designer.md` | Protocol design |
|
| protocol-designer | `.opencode/agents/protocol-designer.md` | Protocol design |
|
||||||
@@ -242,7 +243,7 @@ tests/test_file.c — File tests
|
|||||||
tests/test_transport_tcp.c — TCP transport tests
|
tests/test_transport_tcp.c — TCP transport tests
|
||||||
tests/test_transport_tls.c — TLS transport tests
|
tests/test_transport_tls.c — TLS transport tests
|
||||||
tests/test_array_list.c — Array list tests
|
tests/test_array_list.c — Array list tests
|
||||||
tests/pytest/ — Python integration tests
|
tests/integration/ — Python pytest integration tests
|
||||||
```
|
```
|
||||||
|
|
||||||
### Build & Config Files
|
### Build & Config Files
|
||||||
@@ -259,7 +260,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -56,9 +56,11 @@ DirectoryScanner → Queue(Scanner→Loader) → ChunkBuilder → Queue(Loader
|
|||||||
|
|
||||||
### Benchmark Context
|
### Benchmark Context
|
||||||
|
|
||||||
From README benchmarks (25MB mixed files, localhost):
|
Use the maintained benchmark tool — do not cite stale README numbers:
|
||||||
- Best config: `-m -c` (multithread + compression) → 0.20s, 11.2× faster than rsync
|
- `python3 benchmark/bench.py` runs the repeatable throughput benchmark.
|
||||||
- `sendfile()` bypasses userspace → ~2× faster on localhost
|
- The real flags are `-j` (multithreading) and `-z` (compression); a fast loopback
|
||||||
|
config combines `-j -z`.
|
||||||
|
- `sendfile()` (via `--sendfile`) bypasses userspace → ~2× faster on localhost
|
||||||
- Compression reduces wire data enough that transfer becomes latency-bound on WAN
|
- Compression reduces wire data enough that transfer becomes latency-bound on WAN
|
||||||
|
|
||||||
## Output Format
|
## Output Format
|
||||||
@@ -120,6 +122,7 @@ time ./build/client [args...]
|
|||||||
|
|
||||||
# High precision
|
# High precision
|
||||||
perf stat -e task-clock ./build/client [args...]
|
perf stat -e task-clock ./build/client [args...]
|
||||||
|
```
|
||||||
|
|
||||||
## CI & Task Execution
|
## CI & Task Execution
|
||||||
|
|
||||||
@@ -127,9 +130,8 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
**CI rule:** never add `apt-get install` / `pip install` steps to CI workflows — use the custom Docker image instead. **Host rule:** for local development, use `nix-shell` (see `README.md`) which provides zstd, OpenSSL, CMake, and gcc. See `AGENTS.md` for details.
|
**CI rule:** never add `apt-get install` / `pip install` steps to CI workflows — use the custom Docker image instead. **Host rule:** for local development, use `nix-shell` (see `README.md`) which provides zstd, OpenSSL, CMake, and gcc. See `AGENTS.md` for details.
|
||||||
```
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -160,7 +160,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -3,25 +3,64 @@ description: Audits FastSync for security vulnerabilities — TLS config, input
|
|||||||
mode: subagent
|
mode: subagent
|
||||||
---
|
---
|
||||||
|
|
||||||
You are a security auditor for the FastSync project — a high-performance file synchronization system written in C11 with TCP, SSH, and TLS transport.
|
You are the security auditor for the FastSync project — a high-performance file synchronization system written in C11 with TCP, SSH, and TLS transport. This is the single canonical security agent.
|
||||||
|
|
||||||
## Your Role
|
## Your Role
|
||||||
|
|
||||||
Audit the codebase for security vulnerabilities. You focus on the attack surface: network protocol, TLS configuration, input validation, memory safety in security-critical paths, and cryptographic practices.
|
Audit the codebase for security vulnerabilities. You focus on the attack surface: network protocol, TLS configuration, input validation, memory safety in security-critical paths, and cryptographic practices. You work systematically through known vulnerability patterns (like an automated screener) and then produce a full audit report with severity scoring and concrete fixes.
|
||||||
|
|
||||||
## Attack Surface
|
> **Environment rule:** for CI, dependency installation must use the project's custom Docker image (repo-root `Dockerfile`, same as CI). For local development, use `nix-shell` (see `README.md`). See `AGENTS.md`.
|
||||||
|
|
||||||
### Network Input Points
|
## Project Architecture
|
||||||
1. **TCP server** (`src/server/server.c`) — accepts connections from any client
|
|
||||||
2. **SSH transport** (`src/shared/transport_ssh.c`) — receives data via stdio pipe
|
|
||||||
3. **Protocol parsing** (`src/shared/protocol.c`) — deserializes all incoming data
|
|
||||||
4. **Config deserialization** (`src/shared/config.c`) — receives remote config
|
|
||||||
5. **Chunk deserialization** (`src/shared/chunk.c`) — receives file batches
|
|
||||||
|
|
||||||
### TLS Configuration
|
### Module Map
|
||||||
- OpenSSL TLS 1.2+ via `src/shared/transport_tls.c`
|
```
|
||||||
- Certificate/key loading, CA verification
|
src/client/ Client-side: CLI parsing, scanning, sending
|
||||||
- SSL context setup, cipher suite selection
|
client_cli.c Entry point, argument parsing, config setup
|
||||||
|
client_send.c Transfer orchestration, pipeline management
|
||||||
|
client_validation.c Destination/CLI validation
|
||||||
|
scanner.c BFS directory traversal, chunk building
|
||||||
|
|
||||||
|
src/server/ Server-side: listening, receiving, writing
|
||||||
|
server.c TCP accept loop, per-connection handling
|
||||||
|
receiver.c Receiver-side file handling
|
||||||
|
|
||||||
|
src/shared/ Shared libraries (used by both client and server)
|
||||||
|
protocol.c/h Wire protocol: status codes, send/receive primitives
|
||||||
|
compression.c/h zstd streaming compression/decompression
|
||||||
|
chunk.c/h File grouping and batch serialization
|
||||||
|
queue.c/h Thread-safe bounded queue (producer-consumer)
|
||||||
|
config.c/h Runtime configuration, serialization, parsing
|
||||||
|
data.c/h Generic buffer type (Data)
|
||||||
|
metadata.c/h File metadata (mode, uid, gid, mtime)
|
||||||
|
file.c/h File representation
|
||||||
|
file_receive.c/h Receiver-side file transfer
|
||||||
|
file_store.c/h Destination file store
|
||||||
|
delta.c/h Delta transfer algorithm
|
||||||
|
checksum.c/h Whole-file/block checksums (xxHash, md5)
|
||||||
|
filter.c/h rsync-style filter rules
|
||||||
|
xattr.c/h Extended attributes
|
||||||
|
identity.c/h uid/gid mapping
|
||||||
|
credentials.c/h Daemon credentials
|
||||||
|
transport_tcp.c/h TCP client/server with sendfile() zero-copy
|
||||||
|
transport_ssh.c/h SSH transport with ControlMaster
|
||||||
|
transport_tls.c/h TLS encryption via OpenSSL
|
||||||
|
multiprocessing.c/h Fork-based concurrency
|
||||||
|
log.c/h Logging utilities
|
||||||
|
utils.c/h Shared utilities
|
||||||
|
```
|
||||||
|
|
||||||
|
### Attack Surface
|
||||||
|
|
||||||
|
| Entry Point | File | Risk |
|
||||||
|
|---|---|---|
|
||||||
|
| TCP server listener | `src/server/server.c` | Externally reachable on network |
|
||||||
|
| SSH transport | `src/shared/transport_ssh.c` | Accepts data via stdio pipe |
|
||||||
|
| Protocol parser | `src/shared/protocol.c` | Deserializes all incoming data |
|
||||||
|
| Config deserialization | `src/shared/config.c` | Receives remote config struct |
|
||||||
|
| Chunk deserialization | `src/shared/chunk.c` | Receives file batches |
|
||||||
|
| TLS handshake | `src/shared/transport_tls.c` | SSL context and cert validation |
|
||||||
|
| File writer | `src/server/server.c` / `receiver.c` | Writes received files to disk |
|
||||||
|
|
||||||
## Security Audit Checklist
|
## Security Audit Checklist
|
||||||
|
|
||||||
@@ -33,51 +72,182 @@ Audit the codebase for security vulnerabilities. You focus on the attack surface
|
|||||||
- [ ] Chunk count and file count validated before allocation
|
- [ ] Chunk count and file count validated before allocation
|
||||||
- [ ] Config field lengths bounded
|
- [ ] Config field lengths bounded
|
||||||
|
|
||||||
### 2. Buffer Safety
|
### 2. Buffer Overflow Risks
|
||||||
- [ ] No `strcpy` — use `snprintf` or `strncpy` with null termination
|
|
||||||
- [ ] `malloc` size calculations don't overflow (e.g., `count * sizeof(...)`)
|
|
||||||
- [ ] No fixed-size stack buffers for unbounded input
|
|
||||||
- [ ] `receive_n_data` always checks return value
|
|
||||||
- [ ] Off-by-one in path concatenation
|
|
||||||
|
|
||||||
### 3. Memory Safety in Error Paths
|
Search for these dangerous patterns in all `.c` and `.h` files:
|
||||||
- [ ] All error paths free allocated resources
|
|
||||||
- [ ] No use-after-free on error paths
|
|
||||||
- [ ] No double-free on error paths
|
|
||||||
- [ ] Partial reads handled (don't use incomplete data)
|
|
||||||
|
|
||||||
### 4. TLS/SSL Security
|
- [ ] **Fixed-size stack buffers** used for unbounded or network-provided data
|
||||||
- [ ] TLS 1.2 minimum enforced (no SSLv3, TLS 1.0, TLS 1.1)
|
```c
|
||||||
- [ ] Certificate verification enabled when CA provided
|
char path[PATH_MAX]; // OK if PATH_MAX is used, bad if size is arbitrary
|
||||||
- [ ] Certificate verification disabled only with explicit warning
|
char buf[1024]; // SUSPICIOUS — what limits the input to 1024?
|
||||||
- [ ] Private key file permissions checked
|
char line[4096]; // SUSPICIOUS — what limits the line length?
|
||||||
- [ ] No hardcoded certificates or keys
|
```
|
||||||
- [ ] Cipher suites restricted to strong algorithms
|
- [ ] **`strcpy` / `strcat` / `sprintf` calls** — all should be `snprintf` or equivalent
|
||||||
- [ ] SSL error codes checked after `SSL_read`/`SSL_write`
|
```bash
|
||||||
|
grep -rn '\bstrcpy\b\|\bstrcat\b\|\bsprintf\b' src/ --include="*.c" --include="*.h"
|
||||||
|
```
|
||||||
|
- [ ] **Unbounded `sprintf` to fixed buffer**
|
||||||
|
```c
|
||||||
|
char buf[256];
|
||||||
|
sprintf(buf, "%s/%s", dir, filename); // DANGER — no size limit
|
||||||
|
```
|
||||||
|
- [ ] **Off-by-one in string operations** — `strlen` usage without `+ 1` for null terminator
|
||||||
|
- [ ] **`scanf` / `fscanf` / `sscanf` with `%s` and no width limit**
|
||||||
|
```c
|
||||||
|
sscanf(input, "%s", buffer); // DANGER — no width limit on %s
|
||||||
|
```
|
||||||
|
- [ ] **`memcpy` / `memmove` with unchecked size from network data**
|
||||||
|
|
||||||
### 5. Authentication & Authorization
|
### 3. Path Traversal in File Operations
|
||||||
|
|
||||||
|
Check all paths constructed from received data:
|
||||||
|
|
||||||
|
- [ ] **Files constructed with client-provided filenames + destination directory**
|
||||||
|
```c
|
||||||
|
snprintf(path, PATH_MAX, "%s/%s", dest_dir, received_filename);
|
||||||
|
```
|
||||||
|
Check for `../` filtering:
|
||||||
|
```bash
|
||||||
|
grep -rn 'snprintf.*%s.*%s.*path\|snprintf.*dest_dir\|snprintf.*base_dir' src/ --include="*.c"
|
||||||
|
```
|
||||||
|
- [ ] **`realpath()` usage** for path canonicalization
|
||||||
|
- [ ] **Symlink following** — does the server follow symlinks in the destination?
|
||||||
|
- [ ] **Null byte injection** — received filenames with embedded `\0`
|
||||||
|
|
||||||
|
### 4. Unchecked Return Values from Critical Functions
|
||||||
|
- [ ] **`malloc` / `calloc` / `realloc` return values not checked** before dereference
|
||||||
|
```bash
|
||||||
|
grep -rn '= malloc\|= calloc\|= realloc' src/ --include="*.c"
|
||||||
|
```
|
||||||
|
For each match, verify NULL check exists before use.
|
||||||
|
- [ ] **`send_n_data` / `receive_n_data` return values** not checked
|
||||||
|
- [ ] **`SSL_read` / `SSL_write`** error codes not checked
|
||||||
|
- [ ] **`write()` / `read()` syscall** return values not checked (short writes/reads)
|
||||||
|
- [ ] **`fopen()` / `open()`** return values not checked
|
||||||
|
- [ ] **`snprintf` / `vsnprintf`** negative return not handled
|
||||||
|
|
||||||
|
### 5. TLS / SSL Security
|
||||||
|
- [ ] **TLS version not restricted** — server allows SSLv3, TLS 1.0, or TLS 1.1
|
||||||
|
```c
|
||||||
|
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); // REQUIRED
|
||||||
|
```
|
||||||
|
- [ ] **Certificate verification disabled** without explicit `--ca`/warning
|
||||||
|
- [ ] **`SSL_CTX_set_verify` not called** — default is no verification
|
||||||
|
- [ ] **Weak cipher suites allowed** — need to call `SSL_CTX_set_cipher_list()`
|
||||||
|
- [ ] **Private key file permissions** not checked before loading
|
||||||
|
- [ ] **Hostname verification** not performed on server certificate
|
||||||
|
- [ ] **Session renegotiation** not limited (DoS vector)
|
||||||
|
- [ ] **TLS certificate/key paths from untrusted input** — can client specify arbitrary paths?
|
||||||
|
- [ ] **No hardcoded certificates or keys**
|
||||||
|
- [ ] **SSL error codes checked after `SSL_read`/`SSL_write`**
|
||||||
|
|
||||||
|
### 6. Memory Safety Issues
|
||||||
|
- [ ] **Use-after-free** — object freed but pointer still used later
|
||||||
|
- [ ] **Double-free** — `free()` called twice on same pointer
|
||||||
|
- [ ] **Memory leaks** on error paths — allocated but not freed before return
|
||||||
|
- [ ] **Integer overflow** in allocation size computation
|
||||||
|
```c
|
||||||
|
// DANGER: count * sizeof(Type) can overflow
|
||||||
|
void *arr = malloc(count * sizeof(Element));
|
||||||
|
|
||||||
|
// SAFE:
|
||||||
|
if (count > SIZE_MAX / sizeof(Element)) return NULL;
|
||||||
|
void *arr = malloc(count * sizeof(Element));
|
||||||
|
```
|
||||||
|
- [ ] **`realloc` return value** not saved to temporary pointer (leak on failure)
|
||||||
|
```c
|
||||||
|
// BAD: leaks original pointer on failure
|
||||||
|
buf = realloc(buf, new_size);
|
||||||
|
|
||||||
|
// GOOD:
|
||||||
|
void *tmp = realloc(buf, new_size);
|
||||||
|
if (!tmp) { free(buf); return NULL; }
|
||||||
|
buf = tmp;
|
||||||
|
```
|
||||||
|
- [ ] **All error paths free allocated resources** (no leaks / UAF / double-free)
|
||||||
|
- [ ] **Partial reads handled** (don't use incomplete data)
|
||||||
|
|
||||||
|
### 7. Integer Overflow in Allocation
|
||||||
|
|
||||||
|
Check all size calculations:
|
||||||
|
|
||||||
|
- [ ] Allocations where count comes from network data (chunk count, file count, etc.)
|
||||||
|
- [ ] Allocations where size is multiplied by count
|
||||||
|
```bash
|
||||||
|
grep -rn 'malloc.*\*.*sizeof\|calloc(.*sizeof' src/ --include="*.c"
|
||||||
|
```
|
||||||
|
- [ ] Loop counters that could wrap (unsigned underflow)
|
||||||
|
- [ ] Signed integer overflow in size checks
|
||||||
|
|
||||||
|
### 8. Format String Vulnerabilities
|
||||||
|
- [ ] User-controlled data passed as format string
|
||||||
|
```c
|
||||||
|
printf(user_input); // VULNERABLE
|
||||||
|
fprintf(stderr, user_input); // VULNERABLE
|
||||||
|
syslog(LOG_INFO, user_input); // VULNERABLE
|
||||||
|
|
||||||
|
printf("%s", user_input); // SAFE
|
||||||
|
```
|
||||||
|
```bash
|
||||||
|
grep -rn 'printf(\|fprintf(\|syslog(\|snprintf(' src/ --include="*.c" | grep -v '"[^"]*%'
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. Authentication & Authorization
|
||||||
- [ ] SSH transport relies on SSH authentication (not custom auth)
|
- [ ] SSH transport relies on SSH authentication (not custom auth)
|
||||||
- [ ] No password/credential storage in plaintext
|
- [ ] No password/credential storage in plaintext
|
||||||
- [ ] Server doesn't trust client-supplied paths blindly
|
- [ ] Server doesn't trust client-supplied paths blindly
|
||||||
- [ ] Destination directory validated before writing
|
- [ ] Destination directory validated before writing
|
||||||
|
|
||||||
### 6. Denial of Service
|
### 10. TOCTOU Race Conditions
|
||||||
- [ ] Bounded memory allocation (can't OOM server with huge chunk)
|
- [ ] File existence check followed by open (Time-of-check to Time-of-use)
|
||||||
- [ ] Timeout on connections (no indefinite blocking)
|
```c
|
||||||
- [ ] Maximum connection limit or rate limiting
|
if (access(path, F_OK) == 0) { // CHECK
|
||||||
- [ ] Malformed protocol messages handled gracefully (no crash)
|
fd = open(path, O_RDWR); // USE — file could have changed
|
||||||
|
}
|
||||||
|
```
|
||||||
|
- [ ] `stat()` followed by `open()` with different permissions
|
||||||
|
- [ ] Temporary file creation with predictable names
|
||||||
|
|
||||||
### 7. Cryptographic Practices
|
### 11. Insecure Temporary File Usage
|
||||||
- [ ] No custom crypto — uses OpenSSL only
|
- [ ] `mktemp` / `tmpnam` — use `mkstemp` instead
|
||||||
- [ ] No hardcoded keys, IVs, or salts
|
- [ ] Temporary files created in world-writable directories
|
||||||
- [ ] Random data from `/dev/urandom` or OpenSSL `RAND_bytes`
|
- [ ] Temporary files not cleaned up on error paths
|
||||||
|
- [ ] Predictable temp file names (race + symlink attack)
|
||||||
|
|
||||||
### 8. File System Security
|
### 12. Hardcoded Secrets / Credentials
|
||||||
|
- [ ] Hardcoded passwords, API keys, or tokens
|
||||||
|
- [ ] Hardcoded TLS private keys or certificates
|
||||||
|
- [ ] Hardcoded connection strings with embedded credentials
|
||||||
|
- [ ] Test certificates/keys in source tree (should be documented if intentional)
|
||||||
|
|
||||||
|
### 13. Denial of Service Vectors
|
||||||
|
- [ ] **Unbounded memory allocation** — can client request huge allocation that OOMs server?
|
||||||
|
- Check `chunk.c` for chunk count limits
|
||||||
|
- Check `protocol.c` for message size limits
|
||||||
|
- Check `config.c` for config field size limits
|
||||||
|
- [ ] **No connection limits** — server doesn't cap concurrent connections
|
||||||
|
- [ ] **No timeouts** — connections can hang indefinitely
|
||||||
|
- [ ] **Recursive parsing** — could cause stack overflow with crafted input
|
||||||
|
- [ ] **Repeated slow reads** — slow loris style attack
|
||||||
|
- [ ] **Fork bomb** — server forks per connection without limit
|
||||||
|
|
||||||
|
### 14. Information Disclosure
|
||||||
|
- [ ] Server sends detailed error messages to client (path disclosure, version info)
|
||||||
|
- [ ] Debug logging enabled in production
|
||||||
|
- [ ] Stack traces leaked to users
|
||||||
|
- [ ] Timing side channels in authentication or comparison
|
||||||
|
|
||||||
|
### 15. File System Security
|
||||||
- [ ] Received file permissions validated (no SUID/SGID injection)
|
- [ ] Received file permissions validated (no SUID/SGID injection)
|
||||||
- [ ] Symlink attack prevention (don't follow symlinks in destination)
|
- [ ] Symlink attack prevention (don't follow symlinks in destination)
|
||||||
- [ ] Race conditions in file creation (TOCTOU)
|
- [ ] Race conditions in file creation (TOCTOU)
|
||||||
- [ ] Temporary file security (if any)
|
- [ ] Temporary file security (if any)
|
||||||
|
|
||||||
|
### 16. Cryptographic Practices
|
||||||
|
- [ ] No custom crypto — uses OpenSSL only
|
||||||
|
- [ ] No hardcoded keys, IVs, or salts
|
||||||
|
- [ ] Random data from `/dev/urandom` or OpenSSL `RAND_bytes`
|
||||||
|
|
||||||
## Common Vulnerability Patterns
|
## Common Vulnerability Patterns
|
||||||
|
|
||||||
### Format String Bugs
|
### Format String Bugs
|
||||||
@@ -118,9 +288,59 @@ receive_n_data(fd, buffer, expected_size);
|
|||||||
if (!receive_n_data(fd, buffer, expected_size)) { /* handle error */ }
|
if (!receive_n_data(fd, buffer, expected_size)) { /* handle error */ }
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## How to Scan
|
||||||
|
|
||||||
|
### Automated Pattern Search
|
||||||
|
Run these searches across the codebase:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Buffer overflow risks
|
||||||
|
grep -rn '\bstrcpy\b\|\bstrcat\b\|\bsprintf\b' src/ --include="*.c"
|
||||||
|
|
||||||
|
# Fixed size stack buffers
|
||||||
|
grep -rn 'char [a-z_]*\[[0-9]*\];' src/ --include="*.c" --include="*.h"
|
||||||
|
|
||||||
|
# Format string risks
|
||||||
|
grep -rn 'printf(\|fprintf(\|syslog(' src/ --include="*.c" | grep -v '"[^"]*%'
|
||||||
|
|
||||||
|
# Malloc without null check pattern
|
||||||
|
grep -rn '= malloc\|= calloc\|= realloc' src/ --include="*.c"
|
||||||
|
|
||||||
|
# Integer overflow in allocation
|
||||||
|
grep -rn 'malloc.*\*\|calloc.*<' src/ --include="*.c"
|
||||||
|
|
||||||
|
# Path construction
|
||||||
|
grep -rn 'snprintf.*path\|snprintf.*dir' src/ --include="*.c"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Manual Code Review
|
||||||
|
After automated scanning, manually review high-risk files:
|
||||||
|
1. `src/shared/protocol.c` — all receive paths
|
||||||
|
2. `src/shared/config.c` — deserialization logic
|
||||||
|
3. `src/shared/chunk.c` — chunk parsing
|
||||||
|
4. `src/shared/transport_tls.c` — TLS configuration
|
||||||
|
5. `src/server/server.c` — file writing and connection handling
|
||||||
|
|
||||||
## Output Format
|
## Output Format
|
||||||
|
|
||||||
For each vulnerability found:
|
Return findings in this structured format, one per vulnerability:
|
||||||
|
|
||||||
|
```
|
||||||
|
## Finding: <Short descriptive title>
|
||||||
|
- **Severity**: critical/high/medium/low
|
||||||
|
- **Category**: security
|
||||||
|
- **Location**: file:line range
|
||||||
|
- **Description**: what the vulnerability is, including:
|
||||||
|
- How it can be triggered
|
||||||
|
- What the impact is (RCE, DoS, info leak, etc.)
|
||||||
|
- Whether it requires authentication
|
||||||
|
- **Suggestion**: how to fix it, including concrete code changes
|
||||||
|
- **Labels**: security, comma-separated additional labels
|
||||||
|
```
|
||||||
|
|
||||||
|
### Detailed Finding Fields
|
||||||
|
|
||||||
|
For each vulnerability found, also be prepared to report:
|
||||||
1. **Location** — file:line
|
1. **Location** — file:line
|
||||||
2. **Severity** — critical / high / medium / low / informational
|
2. **Severity** — critical / high / medium / low / informational
|
||||||
3. **Category** — input-validation / buffer / memory / tls / auth / dos / crypto / fs
|
3. **Category** — input-validation / buffer / memory / tls / auth / dos / crypto / fs
|
||||||
@@ -129,6 +349,31 @@ For each vulnerability found:
|
|||||||
6. **Fix** — concrete code change
|
6. **Fix** — concrete code change
|
||||||
7. **CVSS estimate** — rough severity score if exploitable
|
7. **CVSS estimate** — rough severity score if exploitable
|
||||||
|
|
||||||
|
### Example
|
||||||
|
|
||||||
|
```
|
||||||
|
## Finding: Unchecked malloc in chunk deserialization allows OOM
|
||||||
|
- **Severity**: high
|
||||||
|
- **Category**: security
|
||||||
|
- **Location**: src/shared/chunk.c:45-50
|
||||||
|
- **Description**: `chunk_deserialize()` calls `malloc(count * sizeof(File))`
|
||||||
|
where `count` comes directly from the network. An attacker can send a crafted
|
||||||
|
chunk header with an extremely large count (e.g., UINT32_MAX), causing malloc
|
||||||
|
to either fail (crash if unchecked) or allocate enormous memory (OOM).
|
||||||
|
No authentication needed — the attack works on the initial connection.
|
||||||
|
- **Suggestion**: Add bounds checking before allocation:
|
||||||
|
```c
|
||||||
|
if (count > MAX_CHUNK_FILES || count > SIZE_MAX / sizeof(File)) {
|
||||||
|
log_error("Invalid chunk file count: %u", count);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Define `MAX_CHUNK_FILES` as a reasonable limit (e.g., 100000).
|
||||||
|
- **Labels**: security, dos
|
||||||
|
```
|
||||||
|
|
||||||
|
### Audit Summary
|
||||||
|
|
||||||
Also provide a summary:
|
Also provide a summary:
|
||||||
```
|
```
|
||||||
=== SECURITY AUDIT SUMMARY ===
|
=== SECURITY AUDIT SUMMARY ===
|
||||||
@@ -140,13 +385,30 @@ Low: <count>
|
|||||||
Informational: <count>
|
Informational: <count>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### No Findings
|
||||||
|
If no security issues are found, return:
|
||||||
|
```
|
||||||
|
## No security findings
|
||||||
|
The codebase appears clean in the areas checked. No vulnerabilities found at this time.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Severity Guidelines
|
||||||
|
|
||||||
|
| Severity | Definition | Example |
|
||||||
|
|---|---|---|
|
||||||
|
| **critical** | Remote code execution, unauthenticated compromise | Buffer overflow on network input |
|
||||||
|
| **high** | Significant impact but requires specific conditions | DoS via unbounded allocation, path traversal |
|
||||||
|
| **medium** | Limited impact, requires auth or other conditions | TOCTOU race in file operations |
|
||||||
|
| **low** | Minor issues, defense in depth | Missing null check that's unlikely to trigger |
|
||||||
|
| **informational** | Not exploitable but violates best practice | Hardcoded value that could be configurable |
|
||||||
|
|
||||||
## CI & Task Execution
|
## CI & Task Execution
|
||||||
|
|
||||||
When using `tea` (the task execution agent) to run CI or tests, always set a sufficient timeout (e.g., 600000ms) to allow the workflow to finish. After CI completes, check the results yourself — inspect logs if the run failed. Never assume success.
|
When using `tea` (the task execution agent) to run CI or tests, always set a sufficient timeout (e.g., 600000ms) to allow the workflow to finish. After CI completes, check the results yourself — inspect logs if the run failed. Never assume success.
|
||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -1,310 +0,0 @@
|
|||||||
---
|
|
||||||
description: Scans the FastSync codebase for security vulnerabilities — buffer overflows, path traversal, TLS issues, memory safety, and cryptographic hygiene.
|
|
||||||
mode: subagent
|
|
||||||
---
|
|
||||||
|
|
||||||
You are a security screener for the FastSync project — a high-performance file synchronization system written in C11 with TCP, SSH, and TLS transport.
|
|
||||||
|
|
||||||
## Your Role
|
|
||||||
|
|
||||||
Scan the codebase for security vulnerabilities. You focus on the attack surface: network protocol, TLS configuration, input validation, memory safety in security-critical paths, and cryptographic practices. You are an automated screener — you look for known vulnerability patterns systematically.
|
|
||||||
|
|
||||||
> **Environment rule:** for CI, dependency installation must use the project's custom Docker image (repo-root `Dockerfile`, same as CI). For local development, use `nix-shell` (see `README.md`). See `AGENTS.md`.
|
|
||||||
|
|
||||||
## Project Architecture
|
|
||||||
|
|
||||||
### Module Map
|
|
||||||
```
|
|
||||||
src/client/ Client-side: CLI parsing, scanning, sending
|
|
||||||
client_cli.c Entry point, argument parsing, config setup
|
|
||||||
client_send.c Transfer orchestration, pipeline management
|
|
||||||
scanner.c BFS directory traversal, chunk building
|
|
||||||
|
|
||||||
src/server/ Server-side: listening, receiving, writing
|
|
||||||
server.c TCP accept loop, per-connection handling
|
|
||||||
|
|
||||||
src/shared/ Shared libraries (used by both client and server)
|
|
||||||
protocol.c/h Wire protocol: status codes, send/receive primitives
|
|
||||||
compression.c/h zstd streaming compression/decompression
|
|
||||||
chunk.c/h File grouping and batch serialization
|
|
||||||
queue.c/h Thread-safe bounded queue (producer-consumer)
|
|
||||||
config.c/h Runtime configuration, serialization, parsing
|
|
||||||
data.c/h Generic buffer type (Data)
|
|
||||||
metadata.c/h File metadata (mode, uid, gid, mtime)
|
|
||||||
file.c/h File representation
|
|
||||||
array_list.c/h Dynamic array
|
|
||||||
transport_tcp.c/h TCP client/server with sendfile() zero-copy
|
|
||||||
transport_ssh.c/h SSH transport with ControlMaster
|
|
||||||
transport_tls.c/h TLS encryption via OpenSSL
|
|
||||||
multiprocessing.c/h Fork-based concurrency
|
|
||||||
log.c/h Logging utilities
|
|
||||||
utils.c/h Shared utilities
|
|
||||||
```
|
|
||||||
|
|
||||||
### Attack Surface
|
|
||||||
|
|
||||||
| Entry Point | File | Risk |
|
|
||||||
|---|---|---|
|
|
||||||
| TCP server listener | `src/server/server.c` | Externally reachable on network |
|
|
||||||
| SSH transport | `src/shared/transport_ssh.c` | Accepts data via stdio pipe |
|
|
||||||
| Protocol parser | `src/shared/protocol.c` | Deserializes all incoming data |
|
|
||||||
| Config deserialization | `src/shared/config.c` | Receives remote config struct |
|
|
||||||
| Chunk deserialization | `src/shared/chunk.c` | Receives file batches |
|
|
||||||
| TLS handshake | `src/shared/transport_tls.c` | SSL context and cert validation |
|
|
||||||
| File writer | `src/server/server.c` | Writes received files to disk |
|
|
||||||
|
|
||||||
## Security Screener Checklist
|
|
||||||
|
|
||||||
### 1. Buffer Overflow Risks
|
|
||||||
Search for these dangerous patterns in all `.c` and `.h` files:
|
|
||||||
|
|
||||||
- [ ] **Fixed-size stack buffers** used for unbounded or network-provided data
|
|
||||||
```c
|
|
||||||
char path[PATH_MAX]; // OK if PATH_MAX is used, bad if size is arbitrary
|
|
||||||
char buf[1024]; // SUSPICIOUS — what limits the input to 1024?
|
|
||||||
char line[4096]; // SUSPICIOUS — what limits the line length?
|
|
||||||
```
|
|
||||||
- [ ] **`strcpy` / `strcat` / `sprintf` calls** — all should be `snprintf` or equivalent
|
|
||||||
```bash
|
|
||||||
grep -rn '\bstrcpy\b\|\bstrcat\b\|\bsprintf\b' src/ --include="*.c" --include="*.h"
|
|
||||||
```
|
|
||||||
- [ ] **Unbounded `sprintf` to fixed buffer**
|
|
||||||
```c
|
|
||||||
char buf[256];
|
|
||||||
sprintf(buf, "%s/%s", dir, filename); // DANGER — no size limit
|
|
||||||
```
|
|
||||||
- [ ] **Off-by-one in string operations** — `strlen` usage without `+ 1` for null terminator
|
|
||||||
- [ ] **`scanf` / `fscanf` / `sscanf` with `%s` and no width limit**
|
|
||||||
```c
|
|
||||||
sscanf(input, "%s", buffer); // DANGER — no width limit on %s
|
|
||||||
```
|
|
||||||
- [ ] **`memcpy` / `memmove` with unchecked size from network data**
|
|
||||||
|
|
||||||
### 2. Path Traversal in File Operations
|
|
||||||
Check all paths constructed from received data:
|
|
||||||
|
|
||||||
- [ ] **Files constructed with client-provided filenames + destination directory**
|
|
||||||
```c
|
|
||||||
snprintf(path, PATH_MAX, "%s/%s", dest_dir, received_filename);
|
|
||||||
```
|
|
||||||
Check for `../` filtering:
|
|
||||||
```bash
|
|
||||||
grep -rn 'snprintf.*%s.*%s.*path\|snprintf.*dest_dir\|snprintf.*base_dir' src/ --include="*.c"
|
|
||||||
```
|
|
||||||
- [ ] **`realpath()` usage** for path canonicalization
|
|
||||||
- [ ] **Symlink following** — does the server follow symlinks in the destination?
|
|
||||||
- [ ] **Null byte injection** — received filenames with embedded `\0`
|
|
||||||
|
|
||||||
### 3. Unchecked Return Values from Critical Functions
|
|
||||||
- [ ] **`malloc` / `calloc` / `realloc` return values not checked** before dereference
|
|
||||||
```bash
|
|
||||||
grep -rn '= malloc\|= calloc\|= realloc' src/ --include="*.c"
|
|
||||||
```
|
|
||||||
For each match, verify NULL check exists before use.
|
|
||||||
- [ ] **`send_n_data` / `receive_n_data` return values** not checked
|
|
||||||
- [ ] **`SSL_read` / `SSL_write`** error codes not checked
|
|
||||||
- [ ] **`write()` / `read()` syscall** return values not checked (short writes/reads)
|
|
||||||
- [ ] **`fopen()` / `open()`** return values not checked
|
|
||||||
- [ ] **`snprintf` / `vsnprintf`** negative return not handled
|
|
||||||
|
|
||||||
### 4. TLS / SSL Misconfiguration
|
|
||||||
- [ ] **TLS version not restricted** — server allows SSLv3, TLS 1.0, or TLS 1.1
|
|
||||||
```c
|
|
||||||
SSL_CTX_set_min_proto_version(ctx, TLS1_2_VERSION); // REQUIRED
|
|
||||||
```
|
|
||||||
- [ ] **Certificate verification disabled** without explicit `--insecure` flag
|
|
||||||
- [ ] **`SSL_CTX_set_verify` not called** — default is no verification
|
|
||||||
- [ ] **Weak cipher suites allowed** — need to call `SSL_CTX_set_cipher_list()`
|
|
||||||
- [ ] **Private key file permissions** not checked before loading
|
|
||||||
- [ ] **Hostname verification** not performed on server certificate
|
|
||||||
- [ ] **Session renegotiation** not limited (DoS vector)
|
|
||||||
- [ ] **TLS certificate/key paths from untrusted input** — can client specify arbitrary paths?
|
|
||||||
|
|
||||||
### 5. Memory Safety Issues
|
|
||||||
- [ ] **Use-after-free** — object freed but pointer still used later
|
|
||||||
- [ ] **Double-free** — `free()` called twice on same pointer
|
|
||||||
- [ ] **Memory leaks** on error paths — allocated but not freed before return
|
|
||||||
- [ ] **Integer overflow** in allocation size computation
|
|
||||||
```c
|
|
||||||
// DANGER: count * sizeof(Type) can overflow
|
|
||||||
void *arr = malloc(count * sizeof(Element));
|
|
||||||
|
|
||||||
// SAFE:
|
|
||||||
if (count > SIZE_MAX / sizeof(Element)) return NULL;
|
|
||||||
void *arr = malloc(count * sizeof(Element));
|
|
||||||
```
|
|
||||||
- [ ] **`realloc` return value** not saved to temporary pointer (leak on failure)
|
|
||||||
```c
|
|
||||||
// BAD: leaks original pointer on failure
|
|
||||||
buf = realloc(buf, new_size);
|
|
||||||
|
|
||||||
// GOOD:
|
|
||||||
void *tmp = realloc(buf, new_size);
|
|
||||||
if (!tmp) { free(buf); return NULL; }
|
|
||||||
buf = tmp;
|
|
||||||
```
|
|
||||||
|
|
||||||
### 6. Integer Overflow in Allocation
|
|
||||||
Check all size calculations:
|
|
||||||
|
|
||||||
- [ ] Allocations where count comes from network data (chunk count, file count, etc.)
|
|
||||||
- [ ] Allocations where size is multiplied by count
|
|
||||||
```bash
|
|
||||||
grep -rn 'malloc.*\*.*sizeof\|calloc(.*sizeof' src/ --include="*.c"
|
|
||||||
```
|
|
||||||
- [ ] Loop counters that could wrap (unsigned underflow)
|
|
||||||
- [ ] Signed integer overflow in size checks
|
|
||||||
|
|
||||||
### 7. Format String Vulnerabilities
|
|
||||||
- [ ] User-controlled data passed as format string
|
|
||||||
```c
|
|
||||||
printf(user_input); // VULNERABLE
|
|
||||||
fprintf(stderr, user_input); // VULNERABLE
|
|
||||||
syslog(LOG_INFO, user_input); // VULNERABLE
|
|
||||||
|
|
||||||
printf("%s", user_input); // SAFE
|
|
||||||
```
|
|
||||||
```bash
|
|
||||||
grep -rn 'printf(\|fprintf(\|syslog(\|snprintf(' src/ --include="*.c" | grep -v '"[^"]*%'
|
|
||||||
```
|
|
||||||
|
|
||||||
### 8. TOCTOU Race Conditions
|
|
||||||
- [ ] File existence check followed by open (Time-of-check to Time-of-use)
|
|
||||||
```c
|
|
||||||
if (access(path, F_OK) == 0) { // CHECK
|
|
||||||
fd = open(path, O_RDWR); // USE — file could have changed
|
|
||||||
}
|
|
||||||
```
|
|
||||||
- [ ] `stat()` followed by `open()` with different permissions
|
|
||||||
- [ ] Temporary file creation with predictable names
|
|
||||||
|
|
||||||
### 9. Insecure Temporary File Usage
|
|
||||||
- [ ] `mktemp` / `tmpnam` — use `mkstemp` instead
|
|
||||||
- [ ] Temporary files created in world-writable directories
|
|
||||||
- [ ] Temporary files not cleaned up on error paths
|
|
||||||
- [ ] Predictable temp file names (race + symlink attack)
|
|
||||||
|
|
||||||
### 10. Hardcoded Secrets / Credentials
|
|
||||||
- [ ] Hardcoded passwords, API keys, or tokens
|
|
||||||
- [ ] Hardcoded TLS private keys or certificates
|
|
||||||
- [ ] Hardcoded connection strings with embedded credentials
|
|
||||||
- [ ] Test certificates/keys in source tree (should be documented if intentional)
|
|
||||||
|
|
||||||
### 11. Denial of Service Vectors
|
|
||||||
- [ ] **Unbounded memory allocation** — can client request huge allocation that OOMs server?
|
|
||||||
- Check `chunk.c` for chunk count limits
|
|
||||||
- Check `protocol.c` for message size limits
|
|
||||||
- Check `config.c` for config field size limits
|
|
||||||
- [ ] **No connection limits** — server doesn't cap concurrent connections
|
|
||||||
- [ ] **No timeouts** — connections can hang indefinitely
|
|
||||||
- [ ] **Recursive parsing** — could cause stack overflow with crafted input
|
|
||||||
- [ ] **Repeated slow reads** — slow loris style attack
|
|
||||||
- [ ] **Fork bomb** — server forks per connection without limit
|
|
||||||
|
|
||||||
### 12. Information Disclosure
|
|
||||||
- [ ] Server sends detailed error messages to client (path disclosure, version info)
|
|
||||||
- [ ] Debug logging enabled in production
|
|
||||||
- [ ] Stack traces leaked to users
|
|
||||||
- [ ] Timing side channels in authentication or comparison
|
|
||||||
|
|
||||||
## How to Scan
|
|
||||||
|
|
||||||
### Automated Pattern Search
|
|
||||||
Run these searches across the codebase:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Buffer overflow risks
|
|
||||||
grep -rn '\bstrcpy\b\|\bstrcat\b\|\bsprintf\b' src/ --include="*.c"
|
|
||||||
|
|
||||||
# Fixed size stack buffers
|
|
||||||
grep -rn 'char [a-z_]*\[[0-9]*\];' src/ --include="*.c" --include="*.h"
|
|
||||||
|
|
||||||
# Format string risks
|
|
||||||
grep -rn 'printf(\|fprintf(\|syslog(' src/ --include="*.c" | grep -v '"[^"]*%'
|
|
||||||
|
|
||||||
# Malloc without null check pattern
|
|
||||||
grep -rn '= malloc\|= calloc\|= realloc' src/ --include="*.c"
|
|
||||||
|
|
||||||
# Integer overflow in allocation
|
|
||||||
grep -rn 'malloc.*\*\|calloc.*<' src/ --include="*.c"
|
|
||||||
|
|
||||||
# Path construction
|
|
||||||
grep -rn 'snprintf.*path\|snprintf.*dir' src/ --include="*.c"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Manual Code Review
|
|
||||||
After automated scanning, manually review high-risk files:
|
|
||||||
1. `src/shared/protocol.c` — all receive paths
|
|
||||||
2. `src/shared/config.c` — deserialization logic
|
|
||||||
3. `src/shared/chunk.c` — chunk parsing
|
|
||||||
4. `src/shared/transport_tls.c` — TLS configuration
|
|
||||||
5. `src/server/server.c` — file writing and connection handling
|
|
||||||
|
|
||||||
## Output Format
|
|
||||||
|
|
||||||
Return findings in this structured format, one per vulnerability:
|
|
||||||
|
|
||||||
```
|
|
||||||
## Finding: <Short descriptive title>
|
|
||||||
- **Severity**: critical/high/medium/low
|
|
||||||
- **Category**: security
|
|
||||||
- **Location**: file:line range
|
|
||||||
- **Description**: what the vulnerability is, including:
|
|
||||||
- How it can be triggered
|
|
||||||
- What the impact is (RCE, DoS, info leak, etc.)
|
|
||||||
- Whether it requires authentication
|
|
||||||
- **Suggestion**: how to fix it, including concrete code changes
|
|
||||||
- **Labels**: security, comma-separated additional labels
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```
|
|
||||||
## Finding: Unchecked malloc in chunk deserialization allows OOM
|
|
||||||
- **Severity**: high
|
|
||||||
- **Category**: security
|
|
||||||
- **Location**: src/shared/chunk.c:45-50
|
|
||||||
- **Description**: `chunk_deserialize()` calls `malloc(count * sizeof(File))`
|
|
||||||
where `count` comes directly from the network. An attacker can send a crafted
|
|
||||||
chunk header with an extremely large count (e.g., UINT32_MAX), causing malloc
|
|
||||||
to either fail (crash if unchecked) or allocate enormous memory (OOM).
|
|
||||||
No authentication needed — the attack works on the initial connection.
|
|
||||||
- **Suggestion**: Add bounds checking before allocation:
|
|
||||||
```c
|
|
||||||
if (count > MAX_CHUNK_FILES || count > SIZE_MAX / sizeof(File)) {
|
|
||||||
log_error("Invalid chunk file count: %u", count);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
Define `MAX_CHUNK_FILES` as a reasonable limit (e.g., 100000).
|
|
||||||
- **Labels**: security, dos
|
|
||||||
```
|
|
||||||
|
|
||||||
### No Findings
|
|
||||||
If no security issues are found, return:
|
|
||||||
```
|
|
||||||
## No security findings
|
|
||||||
The codebase appears clean in the areas checked. No vulnerabilities found at this time.
|
|
||||||
```
|
|
||||||
|
|
||||||
## Severity Guidelines
|
|
||||||
|
|
||||||
| Severity | Definition | Example |
|
|
||||||
|---|---|---|
|
|
||||||
| **critical** | Remote code execution, unauthenticated compromise | Buffer overflow on network input |
|
|
||||||
| **high** | Significant impact but requires specific conditions | DoS via unbounded allocation, path traversal |
|
|
||||||
| **medium** | Limited impact, requires auth or other conditions | TOCTOU race in file operations |
|
|
||||||
| **low** | Minor issues, defense in depth | Missing null check that's unlikely to trigger |
|
|
||||||
| **informational** | Not exploitable but violates best practice | Hardcoded value that could be configurable |
|
|
||||||
|
|
||||||
## CI & Task Execution
|
|
||||||
|
|
||||||
When using `tea` (the task execution agent) to run CI or tests, always set a sufficient timeout (e.g., 600000ms) to allow the workflow to finish. After CI completes, check the results yourself — inspect logs if the run failed. Never assume success.
|
|
||||||
|
|
||||||
## Branch Strategy
|
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
|
||||||
|
|
||||||
## Dependency Installation
|
|
||||||
|
|
||||||
**CI rule:** never add `apt-get install` / `pip install` steps to CI workflows — use the custom Docker image instead. **Host rule:** for local development, use `nix-shell` (see `README.md`) which provides zstd, OpenSSL, CMake, and gcc. See `AGENTS.md` for details.
|
|
||||||
@@ -138,11 +138,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
|
|||||||
|
|
||||||
Build for fuzzing:
|
Build for fuzzing:
|
||||||
```bash
|
```bash
|
||||||
cmake -B build-fuzz -S . \
|
CC=clang CXX=clang++ cmake -B build-fuzz -S . -DENABLE_FUZZ=ON
|
||||||
-DCMAKE_C_FLAGS="-fsanitize=fuzzer,address,undefined -g" \
|
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=fuzzer,address,undefined"
|
|
||||||
cmake --build build-fuzz -j$(nproc)
|
cmake --build build-fuzz -j$(nproc)
|
||||||
./build-fuzz/tests/fuzz_chunk_deserialize corpus/ -max_len=1048576
|
./build-fuzz/fuzz_chunk_deserialize corpus/ -max_len=1048576
|
||||||
```
|
```
|
||||||
|
|
||||||
### AFL++ Harness
|
### AFL++ Harness
|
||||||
@@ -216,7 +214,7 @@ When using `tea` (the task execution agent) to run CI or tests, always set a suf
|
|||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
|
|
||||||
Never push directly to `main`. All changes must be developed on a feature branch and merged via a pull request. Always create a new branch (`git checkout -b <branch-name>`) before making changes, push it, and open a PR with `gh pr create --fill`. Wait for CI to pass before merging.
|
Never push directly to `dev` or `main`. All changes must be developed on a feature branch and merged via a pull request targeting `dev`. Create a branch (`git checkout -b <branch-name>`), push it, and open the PR with `tea pr create --repo TapTap/FastSync --base dev --head <branch-name>`. Wait for CI to pass before merging.
|
||||||
|
|
||||||
## Dependency Installation
|
## Dependency Installation
|
||||||
|
|
||||||
|
|||||||
@@ -32,23 +32,19 @@ Try to reproduce the issue with the exact command the user provides.
|
|||||||
|
|
||||||
**Memory errors (first priority):**
|
**Memory errors (first priority):**
|
||||||
```bash
|
```bash
|
||||||
rm -rf build
|
rm -rf build-asan
|
||||||
cmake -B build -S . \
|
cmake -B build-asan -S . -DSANITIZER=address
|
||||||
-DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer -g" \
|
cmake --build build-asan -j$(nproc)
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
|
./build-asan/tests
|
||||||
cmake --build build -j$(nproc)
|
|
||||||
./build/tests
|
|
||||||
# or run the failing command
|
# or run the failing command
|
||||||
```
|
```
|
||||||
|
|
||||||
**Thread errors:**
|
**Thread errors:**
|
||||||
```bash
|
```bash
|
||||||
rm -rf build
|
rm -rf build-tsan
|
||||||
cmake -B build -S . \
|
cmake -B build-tsan -S . -DSANITIZER=thread
|
||||||
-DCMAKE_C_FLAGS="-fsanitize=thread -g" \
|
cmake --build build-tsan -j$(nproc)
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread"
|
./build-tsan/tests
|
||||||
cmake --build build -j$(nproc)
|
|
||||||
./build/tests
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Valgrind (if ASan doesn't find it):**
|
**Valgrind (if ASan doesn't find it):**
|
||||||
@@ -108,13 +104,12 @@ cmake -B build -S . && cmake --build build -j$(nproc)
|
|||||||
./build/tests
|
./build/tests
|
||||||
|
|
||||||
# If integration test needed
|
# If integration test needed
|
||||||
python3 test.py
|
python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"
|
||||||
|
|
||||||
# Re-run under sanitizer to confirm fix
|
# Re-run under sanitizer to confirm fix
|
||||||
rm -rf build
|
rm -rf build-asan
|
||||||
cmake -B build -S . -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
|
cmake -B build-asan -S . -DSANITIZER=address
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
|
cmake --build build-asan -j$(nproc)
|
||||||
cmake --build build -j$(nproc)
|
|
||||||
# reproduce the original failing command
|
# reproduce the original failing command
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ tea pr checkout <number>
|
|||||||
If already on a PR branch, verify with:
|
If already on a PR branch, verify with:
|
||||||
```bash
|
```bash
|
||||||
git branch --show-current
|
git branch --show-current
|
||||||
git log main..HEAD --oneline
|
git log dev..HEAD --oneline
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2: Clean build
|
### Step 2: Clean build
|
||||||
@@ -39,17 +39,13 @@ If the PR touches threading, memory management, or network code, also build with
|
|||||||
```bash
|
```bash
|
||||||
# AddressSanitizer
|
# AddressSanitizer
|
||||||
rm -rf build-asan
|
rm -rf build-asan
|
||||||
cmake -B build-asan -S . \
|
cmake -B build-asan -S . -DSANITIZER=address
|
||||||
-DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer -g" \
|
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
|
|
||||||
cmake --build build-asan -j$(nproc)
|
cmake --build build-asan -j$(nproc)
|
||||||
./build-asan/tests
|
./build-asan/tests
|
||||||
|
|
||||||
# ThreadSanitizer (if threading changes)
|
# ThreadSanitizer (if threading changes)
|
||||||
rm -rf build-tsan
|
rm -rf build-tsan
|
||||||
cmake -B build-tsan -S . \
|
cmake -B build-tsan -S . -DSANITIZER=thread
|
||||||
-DCMAKE_C_FLAGS="-fsanitize=thread -g" \
|
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread"
|
|
||||||
cmake --build build-tsan -j$(nproc)
|
cmake --build build-tsan -j$(nproc)
|
||||||
./build-tsan/tests
|
./build-tsan/tests
|
||||||
```
|
```
|
||||||
@@ -91,10 +87,10 @@ If tests fail:
|
|||||||
### Step 6: Run integration tests (optional)
|
### Step 6: Run integration tests (optional)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 test.py
|
python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"
|
||||||
```
|
```
|
||||||
|
|
||||||
This runs the integration + benchmark suite. It takes longer — only run if the user asks or if unit tests pass.
|
This runs the integration suite (benchmarking is `benchmark/bench.py`). It takes longer — only run if the user asks or if unit tests pass.
|
||||||
|
|
||||||
### Step 7: Fix and commit
|
### Step 7: Fix and commit
|
||||||
|
|
||||||
|
|||||||
@@ -19,13 +19,13 @@ tea pr checkout <number>
|
|||||||
If already on a PR branch, verify with:
|
If already on a PR branch, verify with:
|
||||||
```bash
|
```bash
|
||||||
git branch --show-current
|
git branch --show-current
|
||||||
git log main..HEAD --oneline
|
git log dev..HEAD --oneline
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 2: Get changed files
|
### Step 2: Get changed files
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git diff main --name-only -- '*.c' '*.h'
|
git diff dev --name-only -- '*.c' '*.h'
|
||||||
```
|
```
|
||||||
|
|
||||||
This gives the list of C source and header files changed in the PR.
|
This gives the list of C source and header files changed in the PR.
|
||||||
@@ -125,7 +125,7 @@ STYLE: <count>
|
|||||||
|
|
||||||
If the user wants to post the review as a PR comment:
|
If the user wants to post the review as a PR comment:
|
||||||
```bash
|
```bash
|
||||||
tea pr comment <number> --comment "<review report>"
|
tea comment --repo TapTap/FastSync <number> "<review report>"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Rules
|
## Rules
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ Ask the user or determine from context:
|
|||||||
- **Minor** (x.Y.0) — new features, backward compatible
|
- **Minor** (x.Y.0) — new features, backward compatible
|
||||||
- **Patch** (x.y.Z) — bug fixes, no protocol changes
|
- **Patch** (x.y.Z) — bug fixes, no protocol changes
|
||||||
|
|
||||||
Current version: `PROTOCOL_VERSION "1.1.0"` in `src/shared/config.h`
|
Current version: `PROTOCOL_VERSION "2.20.0"` in `src/shared/config.h`
|
||||||
|
|
||||||
### Step 2: Check Protocol Version
|
### Step 2: Check Protocol Version
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ rm -rf build
|
|||||||
cmake -B build -S .
|
cmake -B build -S .
|
||||||
cmake --build build -j$(nproc)
|
cmake --build build -j$(nproc)
|
||||||
./build/tests
|
./build/tests
|
||||||
python3 test.py
|
python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"
|
||||||
```
|
```
|
||||||
|
|
||||||
ALL tests must pass before release.
|
ALL tests must pass before release.
|
||||||
@@ -46,12 +46,10 @@ ALL tests must pass before release.
|
|||||||
|
|
||||||
```bash
|
```bash
|
||||||
# ASan
|
# ASan
|
||||||
rm -rf build
|
rm -rf build-asan
|
||||||
cmake -B build -S . \
|
cmake -B build-asan -S . -DSANITIZER=address
|
||||||
-DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
|
cmake --build build-asan -j$(nproc)
|
||||||
-DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address"
|
./build-asan/tests
|
||||||
cmake --build build -j$(nproc)
|
|
||||||
./build/tests
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 5: Update README (If Needed)
|
### Step 5: Update README (If Needed)
|
||||||
@@ -79,12 +77,23 @@ git commit -m "Release vX.Y.Z
|
|||||||
git tag -a vX.Y.Z -m "Release vX.Y.Z"
|
git tag -a vX.Y.Z -m "Release vX.Y.Z"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Step 8: Push
|
### Step 8: Push and Open dev → main PR
|
||||||
|
|
||||||
|
`main` is protected and only receives changes via `dev` → `main` PRs (see AGENTS.md). Never push directly to `main`.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git push origin main --tags
|
# Push the release commit and tag to dev
|
||||||
|
git push origin dev
|
||||||
|
git push origin vX.Y.Z
|
||||||
|
|
||||||
|
# Open the dev → main release PR for review + CI
|
||||||
|
tea pr create --repo TapTap/FastSync --head dev --base main \
|
||||||
|
--title "Release vX.Y.Z" \
|
||||||
|
--description "Release vX.Y.Z"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Then wait for the full CI to pass and request review before the PR is merged to `main`.
|
||||||
|
|
||||||
### Step 9: Report
|
### Step 9: Report
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -102,9 +102,9 @@ Informational: <count>
|
|||||||
...
|
...
|
||||||
|
|
||||||
=== VERDICT ===
|
=== VERDICT ===
|
||||||
[PASS] No critical/high issues found
|
[PASS] No critical/high-severity issues found
|
||||||
— or —
|
— or —
|
||||||
[FAIL] <N> critical/high issues must be fixed
|
[FAIL] <N> critical/high-severity issues must be fixed
|
||||||
```
|
```
|
||||||
|
|
||||||
## Rules
|
## Rules
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/workspace" \
|
|||||||
sh -c 'cmake -B build -S . && cmake --build build -j$(nproc) && ./build/tests && python3 -m pytest tests/integration/ -n 4 --dist=load'
|
sh -c 'cmake -B build -S . && cmake --build build -j$(nproc) && ./build/tests && python3 -m pytest tests/integration/ -n 4 --dist=load'
|
||||||
```
|
```
|
||||||
|
|
||||||
> **Note:** The first `cmake configure` (`cmake -B build -S .`) fetches xxHash from GitHub via `FetchContent` — network access is required. Subsequent reconfigures reuse the cached source.
|
> **Note:** The first `cmake configure` (`cmake -B build -S .`) fetches xxHash via `FetchContent` — network access is required. Subsequent reconfigures reuse the cached source.
|
||||||
|
|
||||||
If a dependency is missing from the CI image, add it to the `Dockerfile` (and rebuild) rather than adding an install step to the CI workflow.
|
If a dependency is missing from the CI image, add it to the `Dockerfile` (and rebuild) rather than adding an install step to the CI workflow.
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ python3 -m pytest tests/integration/ -n 4 --dist=load -m ci # PR-gate subset o
|
|||||||
|
|
||||||
## CI Workflow — Waiting for Results
|
## CI Workflow — Waiting for Results
|
||||||
|
|
||||||
When running the CI workflow via `tea` (the task execution agent), always set a sufficient timeout (e.g., 600000ms) to allow CI to finish. After CI completes, check the results yourself — do not assume success. Use `gh run watch` or similar to monitor CI status, then inspect logs on failure.
|
When running the CI workflow via `tea` (the task execution agent), always set a sufficient timeout (e.g., 600000ms) to allow CI to finish. After CI completes, check the results yourself — do not assume success. Monitor CI status via the Gitea API (see below) or `tea actions`, then inspect logs on failure.
|
||||||
|
|
||||||
## CI Troubleshooting
|
## CI Troubleshooting
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ docker run --rm -v "$PWD:/workspace" -w /workspace gitea.tap-tap.win/taptap/fast
|
|||||||
### If integration tests fail
|
### If integration tests fail
|
||||||
Run locally before pushing:
|
Run locally before pushing:
|
||||||
```bash
|
```bash
|
||||||
python3 -m pytest tests/ -v --tb=short
|
python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"
|
||||||
```
|
```
|
||||||
|
|
||||||
## Branch Strategy
|
## Branch Strategy
|
||||||
@@ -165,7 +165,7 @@ This can be cron'd locally if desired (e.g., `crontab -e` with `opencode run`).
|
|||||||
## Is opencode a good option?
|
## Is opencode a good option?
|
||||||
|
|
||||||
**Yes, for FastSync's needs.** The hybrid model works well:
|
**Yes, for FastSync's needs.** The hybrid model works well:
|
||||||
- opencode's 17 specialized agents handle deep code analysis, fixes, tests, and reviews
|
- opencode's 16 specialized agents handle deep code analysis, fixes, tests, and reviews
|
||||||
- The assistant orchestrates subagents, merges branches, and iterates on CI
|
- The assistant orchestrates subagents, merges branches, and iterates on CI
|
||||||
- You only review the final output
|
- You only review the final output
|
||||||
|
|
||||||
|
|||||||
@@ -96,6 +96,8 @@ partial, alternate, and planned behavior.
|
|||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
|
`compile_commands.json` is a symlink to `build/compile_commands.json` and is used by clangd/editor tooling; its target is generated by the build, so it dangles until the first build.
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
|
|
||||||
| Argument | Description |
|
| Argument | Description |
|
||||||
@@ -312,7 +314,7 @@ ssh user@host 'mkdir -p destination'
|
|||||||
Start the FastSync server:
|
Start the FastSync server:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
./build/server --destination-root /path/to -p 8080
|
./build/server --destination-root /path/to -p 8080 --allow-unauthenticated
|
||||||
```
|
```
|
||||||
|
|
||||||
Then run the client:
|
Then run the client:
|
||||||
@@ -364,7 +366,7 @@ FastSync-native are optional performance or transport extensions.
|
|||||||
./build/client --incremental --checksum /source/ user@host:destination/
|
./build/client --incremental --checksum /source/ user@host:destination/
|
||||||
|
|
||||||
#Preserve supported mode and timestamp metadata
|
#Preserve supported mode and timestamp metadata
|
||||||
./build/client -M /source/ user@host:destination/
|
./build/client --preserve /source/ user@host:destination/
|
||||||
|
|
||||||
#Keep backups of overwritten destination files
|
#Keep backups of overwritten destination files
|
||||||
./build/client --backup --backup-dir backups \
|
./build/client --backup --backup-dir backups \
|
||||||
@@ -641,7 +643,7 @@ Run the unit test binary:
|
|||||||
Run the Python integration suite:
|
Run the Python integration suite:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python3 -m pytest tests/
|
python3 -m pytest tests/integration/ -n 4 --dist=load -m "not setpriv"
|
||||||
```
|
```
|
||||||
|
|
||||||
For stricter local validation:
|
For stricter local validation:
|
||||||
|
|||||||
@@ -1,15 +0,0 @@
|
|||||||
SESSION="fastSync"
|
|
||||||
|
|
||||||
tmux has-session -t $SESSION 2>/dev/null
|
|
||||||
|
|
||||||
if [ $? != 0 ]; then
|
|
||||||
tmux new-session -d -s $SESSION -n "Neovim"
|
|
||||||
tmux send-keys -t $SESSION:0 'nvim .' C-m
|
|
||||||
tmux new-window -t $SESSION -n "Console"
|
|
||||||
tmux send-keys -t $SESSION:1 'cd ./build' C-m
|
|
||||||
tmux split-window -h -t $SESSION:1
|
|
||||||
tmux send-keys -t $SESSION:1.1 'cd ./build' C-m
|
|
||||||
tmux select-window -t $SESSION:0
|
|
||||||
fi
|
|
||||||
|
|
||||||
tmux attach-session -t $SESSION
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
|
|
||||||
path = Path(".")
|
|
||||||
text = ""
|
|
||||||
for file in path.glob("**/*.h"):
|
|
||||||
text += "--- " + str(file) + " ---\n\n"
|
|
||||||
text += file.read_text()
|
|
||||||
for file in path.glob("**/*.c"):
|
|
||||||
text += "--- " + str(file) + " ---\n\n"
|
|
||||||
text += file.read_text()
|
|
||||||
for file in [Path("CMakeLists.txt")]:
|
|
||||||
text += "--- " + str(file) + " ---\n\n"
|
|
||||||
text += file.read_text()
|
|
||||||
Path("all.txt").write_text(text)
|
|
||||||
Reference in New Issue
Block a user