Skip to content

Commit c7ae331

Browse files
committed
Maj CI/CD
1 parent 88e03ed commit c7ae331

6 files changed

Lines changed: 257 additions & 65 deletions

File tree

.github/workflows/Release.yml

Lines changed: 171 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,186 @@
1-
name: Release
1+
name: CI CD
22

3-
on:
3+
on:
44
workflow_dispatch:
5+
pull_request:
56
push:
7+
branches:
8+
- "**"
69
tags:
7-
- '*'
10+
- "*"
811

912
env:
10-
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
13+
BUILD_DIR: build-conan
1114
BUILD_TYPE: Release
15+
RELEASE_TARBALL: Release.tar.gz
16+
RELEASE_ARTIFACT: C2LinuxImplant-Linux-Release
1217

1318
permissions:
14-
contents: write
19+
contents: read
1520

1621
jobs:
17-
buildAndRelease:
18-
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
19-
# You can convert this to a matrix build if you need cross-platform coverage.
20-
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
21-
# compile for old libc to cover more linux versions
22+
build-test:
23+
name: Build and test Linux deliverables
2224
runs-on: ubuntu-22.04
2325

2426
steps:
25-
- uses: actions/checkout@v4
26-
27-
- name: Install Samba client dev headers
28-
run: |
29-
sudo apt-get update
30-
sudo apt-get install -y libsmbclient-dev
31-
32-
# Update references
33-
- name: Git Sumbodule Update
34-
run: |
35-
git submodule update --init
36-
37-
- name: Get Conan
38-
# You may pin to the exact commit or the version.
39-
# uses: turtlebrowser/get-conan@c171f295f3f507360ee018736a6608731aa2109d
40-
uses: turtlebrowser/get-conan@v1.2
41-
42-
- name: Create default profile
43-
run: conan profile detect
44-
45-
- name: Configure CMake
46-
run: cmake -B ${{github.workspace}}/build -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=${{github.workspace}}/conan_provider.cmake
47-
48-
- name: Build
49-
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -j 18
50-
51-
- name: Prep release
52-
shell: bash
53-
run: |
54-
rm ./Release/Beacons/.gitignore
55-
mv ./Release/Beacons ./Release/LinuxBeacons
56-
rm ./Release/Modules/.gitignore
57-
mv ./Release/Modules ./Release/LinuxModules
58-
tar -zcvf Release.tar.gz Release
59-
60-
- name: Upload release
61-
uses: svenstaro/upload-release-action@v2
62-
with:
63-
repo_token: ${{ secrets.GITHUB_TOKEN }}
64-
file: Release.tar.gz
65-
asset_name: Release.tar.gz
66-
tag: ${{ github.ref }}
67-
overwrite: true
68-
body: "Linux beacons and modules"
27+
- name: Checkout
28+
uses: actions/checkout@v4
29+
with:
30+
submodules: recursive
6931

32+
- name: Set up Python
33+
uses: actions/setup-python@v5
34+
with:
35+
python-version: "3.x"
36+
37+
- name: Install Linux dependencies
38+
run: |
39+
sudo apt-get update
40+
sudo apt-get install -y libsmbclient-dev
41+
42+
- name: Install Conan
43+
run: |
44+
python -m pip install --upgrade pip
45+
python -m pip install "conan>=2,<3"
46+
conan profile detect --force
47+
48+
- name: Cache Conan packages
49+
uses: actions/cache@v4
50+
with:
51+
path: ~/.conan2
52+
key: conan-${{ runner.os }}-${{ hashFiles('conanfile.txt') }}
53+
restore-keys: |
54+
conan-${{ runner.os }}-
55+
56+
- name: Configure
57+
run: |
58+
cmake \
59+
-S . \
60+
-B "$BUILD_DIR" \
61+
-DCMAKE_BUILD_TYPE="$BUILD_TYPE" \
62+
-DC2CORE_BUILD_TESTS=ON \
63+
-DCMAKE_PROJECT_TOP_LEVEL_INCLUDES="$GITHUB_WORKSPACE/conan_provider.cmake"
64+
65+
- name: Build
66+
run: cmake --build "$BUILD_DIR" --config "$BUILD_TYPE" --parallel "$(nproc)"
67+
68+
- name: Test
69+
run: ctest --test-dir "$BUILD_DIR" --output-on-failure --timeout 60
70+
71+
- name: Validate deliverables
72+
run: |
73+
set -euo pipefail
74+
75+
expected_beacons=(
76+
BeaconDns
77+
BeaconGithub
78+
BeaconHttp
79+
BeaconSmb
80+
BeaconTcp
81+
)
82+
83+
expected_modules=(
84+
libAssemblyExec.so
85+
libCat.so
86+
libChangeDirectory.so
87+
libChisel.so
88+
libCimExec.so
89+
libCoff.so
90+
libDcomExec.so
91+
libDotnetExec.so
92+
libDownload.so
93+
libEnumerateRdpSessions.so
94+
libEnumerateShares.so
95+
libEvasion.so
96+
libGetEnv.so
97+
libInject.so
98+
libIpConfig.so
99+
libKerberosUseTicket.so
100+
libKeyLogger.so
101+
libKillProcess.so
102+
libListDirectory.so
103+
libListProcesses.so
104+
libMakeToken.so
105+
libMiniDump.so
106+
libMkDir.so
107+
libNetstat.so
108+
libPowershell.so
109+
libPrintWorkingDirectory.so
110+
libPsExec.so
111+
libPwSh.so
112+
libRegistry.so
113+
libRemove.so
114+
libRev2self.so
115+
libRun.so
116+
libScreenShot.so
117+
libScript.so
118+
libShell.so
119+
libSpawnAs.so
120+
libSshExec.so
121+
libStealToken.so
122+
libTaskScheduler.so
123+
libTree.so
124+
libUpload.so
125+
libWhoami.so
126+
libWinRM.so
127+
libWmiExec.so
128+
)
129+
130+
for file in "${expected_beacons[@]}"; do
131+
test -s "Release/Beacons/$file" || {
132+
echo "Missing or empty beacon deliverable: $file" >&2
133+
exit 1
134+
}
135+
done
136+
137+
for file in "${expected_modules[@]}"; do
138+
test -s "Release/Modules/$file" || {
139+
echo "Missing or empty module deliverable: $file" >&2
140+
exit 1
141+
}
142+
done
143+
144+
- name: Stage release archive
145+
run: |
146+
set -euo pipefail
147+
stage="artifacts/Release"
148+
149+
rm -rf artifacts "$RELEASE_TARBALL"
150+
mkdir -p "$stage/LinuxBeacons" "$stage/LinuxModules"
151+
152+
find Release/Beacons -maxdepth 1 -type f ! -name ".gitignore" -exec cp -t "$stage/LinuxBeacons" {} +
153+
find Release/Modules -maxdepth 1 -type f ! -name ".gitignore" -exec cp -t "$stage/LinuxModules" {} +
154+
155+
tar -C artifacts -czf "$RELEASE_TARBALL" Release
156+
157+
- name: Upload CI artifact
158+
uses: actions/upload-artifact@v4
159+
with:
160+
name: ${{ env.RELEASE_ARTIFACT }}
161+
path: ${{ env.RELEASE_TARBALL }}
162+
if-no-files-found: error
163+
164+
release:
165+
name: Publish GitHub release
166+
runs-on: ubuntu-22.04
167+
needs: build-test
168+
if: startsWith(github.ref, 'refs/tags/')
169+
permissions:
170+
contents: write
171+
172+
steps:
173+
- name: Download release archive
174+
uses: actions/download-artifact@v4
175+
with:
176+
name: ${{ env.RELEASE_ARTIFACT }}
177+
178+
- name: Upload release
179+
uses: svenstaro/upload-release-action@v2
180+
with:
181+
repo_token: ${{ secrets.GITHUB_TOKEN }}
182+
file: ${{ env.RELEASE_TARBALL }}
183+
asset_name: ${{ env.RELEASE_TARBALL }}
184+
tag: ${{ github.ref }}
185+
overwrite: true
186+
body: "Linux beacons and modules"

AGENT.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# AGENT.md - C2LinuxImplant
2+
3+
## CI/CD Contract
4+
5+
- CI runs on `pull_request` and every branch push, including tag pushes before release publication.
6+
- CD publishes only from tag builds after the CI build, tests, deliverable validation, and archive staging have succeeded.
7+
- GitHub Actions permissions stay read-only by default. Only the release publication job may request `contents: write`.
8+
9+
## Build and Test Contract
10+
11+
- Linux CI builds with Conan through `conan_provider.cmake`.
12+
- The CI configure step must pass `-DC2CORE_BUILD_TESTS=ON`.
13+
- Tests must be visible from the top-level build directory and run with `ctest --test-dir <build-dir> --output-on-failure --timeout 60`.
14+
- Do not silently skip unstable tests. Fix them when reasonable, or isolate them explicitly with a documented reason.
15+
- `libs/libDns/tests/fonctionalTest` is intentionally not registered in CI because it is a manual server/client harness and exits with usage information unless runtime arguments are provided.
16+
17+
## Release Layout
18+
19+
C2TeamServer consumes Linux release payloads from the archive layout below:
20+
21+
```text
22+
Release/
23+
LinuxBeacons/
24+
BeaconDns
25+
BeaconGithub
26+
BeaconHttp
27+
BeaconSmb
28+
BeaconTcp
29+
LinuxModules/
30+
lib*.so
31+
```
32+
33+
The CMake build may copy intermediate deliverables into `Release/Beacons` and `Release/Modules`, but packaging must not rename, delete, or mutate those source output directories. Stage archives from a clean `artifacts/Release` tree instead.

CMakeLists.txt

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
88
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
99

1010
option(C2CORE_BUILD_TESTS "Enable C2Core tests from the parent project" OFF)
11+
if(C2CORE_BUILD_TESTS)
12+
enable_testing()
13+
endif()
1114

1215
set(C2_RUNTIME_MODULE_OUTPUT_DIR "${CMAKE_SOURCE_DIR}/Release/Modules" CACHE PATH
1316
"Directory where C2Core runtime modules are copied after build")
@@ -28,9 +31,12 @@ add_definitions(-DBUILD_IMPLANT)
2831
set(CMAKE_PREFIX_PATH ${CMAKE_BINARY_DIR})
2932

3033
find_package(OpenSSL REQUIRED)
31-
find_package(httplib REQUIRED)
32-
find_package(Libssh2 REQUIRED)
34+
find_package(httplib REQUIRED)
35+
find_package(Libssh2 REQUIRED)
3336
find_package(nlohmann_json REQUIRED CONFIG)
37+
if(C2CORE_BUILD_TESTS)
38+
find_package(Catch2 REQUIRED CONFIG)
39+
endif()
3440

3541
include_directories(${CMAKE_INCLUDE_PATH})
3642

@@ -46,9 +52,20 @@ endif()
4652

4753
include_directories(thirdParty)
4854

49-
add_subdirectory(libs)
50-
51-
add_subdirectory(thirdParty)
55+
add_subdirectory(libs)
56+
if(C2CORE_BUILD_TESTS)
57+
add_test(NAME dnsTest COMMAND dnsTest)
58+
add_test(NAME utilsTest COMMAND utilsTest)
59+
# fonctionalTest is a manual server/client harness that requires runtime args.
60+
# Keep it built, but do not register it in CI ctest without explicit parameters.
61+
add_test(NAME responseDecodeTest COMMAND responseDecodeTest)
62+
add_test(NAME messageTest COMMAND messageTest)
63+
add_test(NAME interleavedTest COMMAND interleavedTest)
64+
add_test(NAME TestsSockerHandler COMMAND TestsSockerHandler)
65+
add_test(NAME TestsSocksServer COMMAND TestsSocksServer)
66+
endif()
67+
68+
add_subdirectory(thirdParty)
5269
include_directories(thirdParty/base64)
5370
include_directories(thirdParty/donut/include)
5471

@@ -58,10 +75,14 @@ set_target_properties(Donut PROPERTIES
5875
IMPORTED_LOCATION "${DONUT_BUILD_DIR}/lib/libdonut.a"
5976
)
6077

61-
add_subdirectory(core/modules)
62-
add_subdirectory(core/beacon)
63-
64-
include_directories(core/listener)
78+
add_subdirectory(core/modules)
79+
add_subdirectory(core/beacon)
80+
if(C2CORE_BUILD_TESTS)
81+
add_subdirectory(core/beacon/tests)
82+
add_subdirectory(core/listener/tests)
83+
endif()
84+
85+
include_directories(core/listener)
6586
include_directories(core/beacon)
6687
include_directories(core/modules/ModuleCmd)
6788
add_subdirectory(beacon/beacon)

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,23 @@ make -j4
8787

8888
* Compiled Beacons: `Release/Beacons`
8989
* Compiled Modules: `Release/Modules`
90+
91+
### CI/CD Release Contract
92+
93+
CI runs on pull requests and branch pushes. It installs Conan, configures a Release Linux build with `C2CORE_BUILD_TESTS=ON`, builds all Linux beacons/modules, runs `ctest --output-on-failure --timeout 60`, and validates every expected deliverable before archiving.
94+
95+
Release publication runs only from tag builds after CI succeeds. The archive is staged from a clean `artifacts/Release` tree and uses the C2TeamServer-facing layout:
96+
97+
```text
98+
Release/
99+
LinuxBeacons/
100+
BeaconDns
101+
BeaconGithub
102+
BeaconHttp
103+
BeaconSmb
104+
BeaconTcp
105+
LinuxModules/
106+
lib*.so
107+
```
108+
109+
Packaging must not rename, delete, or mutate the CMake output directories `Release/Beacons` and `Release/Modules`; it only copies their non-`.gitignore` contents into staging.

conanfile.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ openssl/3.6.2
33
cpp-httplib/0.39.0
44
libssh2/1.11.1
55
nlohmann_json/3.12.0
6+
catch2/3.14.0
67

78
[options]
89
libssh2/*:shared=False
@@ -11,4 +12,4 @@ libssh2/*:shared=False
1112
cmake_layout
1213

1314
[generators]
14-
CMakeDeps
15+
CMakeDeps

0 commit comments

Comments
 (0)