feat(build): per-build watermark (RELEASE_ID / XC_VM_BUILD_ID)

`make main`/`make lb` now stamp a unique per-build id — version + short git
SHA + UTC timestamp + 8 random bytes — into RELEASE_ID at the staged deploy
root (new stamp_release_id target, run after the copy step; the file is
generated per build, never git-tracked). ConstantsInitializer exposes it at
file scope as XC_VM_BUILD_ID by reading RELEASE_ID relative to __DIR__; a
source/dev checkout has no file and reports 'dev'.

This gives every build a traceable fingerprint so a leaked or rebranded copy
can be tied back to its origin (and, once activation ships, reported in the
phone-home alongside install_id). Kept at file scope to avoid adding a branch
to ConstantsInitializer::init() (CRAP ratchet). README discloses it.

Tests: XC_VM_BUILD_ID defined and defaults to 'dev' in a source checkout.
Full suite (817) + gates + CRAP + phpcs green; Makefile targets validated.
This commit is contained in:
Divarion_D
2026-09-18 15:45:34 +03:00
parent 5ef12b1cde
commit c289352d43
4 changed files with 33 additions and 2 deletions
+14 -2
View File
@@ -243,10 +243,10 @@ generate_deleted_files:
# ─── MAIN targets ────────────────────────────────────────────────
# Single archive: used for both clean install and update.
# The update script (src/update) filters out excluded dirs at runtime.
main: main_copy_files set_permissions verify_no_lfs_pointers create_archive main_archive_move main_install_archive clean
main: main_copy_files stamp_release_id set_permissions verify_no_lfs_pointers create_archive main_archive_move main_install_archive clean
# ─── LoadBalancer targets ────────────────────────────────────────
lb: lb_copy_files lb_delete_files_list set_permissions verify_no_lfs_pointers create_archive lb_archive_move clean
lb: lb_copy_files lb_delete_files_list stamp_release_id set_permissions verify_no_lfs_pointers create_archive lb_archive_move clean
lb_copy_files:
@echo "==> [LB] Creating distribution directory: $(DIST_DIR)"
@@ -316,6 +316,18 @@ main_copy_files:
-delete
@echo "All files gitkeep deleted"
# Stamp a unique per-build watermark into the staged tree for provenance / leak
# tracing. Generated per build (NOT git-tracked, one file per archive). Runtime
# exposes it as the XC_VM_BUILD_ID constant (ConstantsInitializer reads
# RELEASE_ID from the deploy root); a source/dev checkout has no file -> "dev".
stamp_release_id:
@ver=$$(sed -nE "s/.*define\('XC_VM_VERSION', '([^']+)'\).*/\1/p" $(MAIN_DIR)/Core/Config/ConstantsInitializer.php | head -n1); \
sha=$$(git rev-parse --short=10 HEAD 2>/dev/null || echo nogit); \
rnd=$$(od -An -N8 -tx1 /dev/urandom | tr -d ' \n'); \
id="$${ver:-0}+$${sha}.$$(date -u +%Y%m%dT%H%M%SZ).$${rnd}"; \
printf '%s\n' "$$id" > "$(TEMP_DIR)/RELEASE_ID"; \
echo "==> [BUILD] Stamped RELEASE_ID: $$id"
lb_delete_files_list:
@echo "[INFO] Checking for manual deleted files list (LB-scoped)"
@if [ -f "$(MAIN_DIR)/migrations/deleted_files.txt" ]; then \
+3
View File
@@ -331,6 +331,9 @@ credit shown in the panel footer — is still present. If the notice has been re
non-destructive: no data is modified, the CLI remains available, and restoring the notice
unlocks the panel on the next request. End-viewer streaming is **not** affected by this check.
Each build is also stamped with a unique build identifier (`XC_VM_BUILD_ID`) for provenance,
so a leaked or rebranded copy can be traced back to the build it originated from.
> ⚖️ You are solely responsible for how it is used.
> We take no responsibility for misuse or illegal deployments.
+9
View File
@@ -12,6 +12,15 @@ defined('DB_ACCESS_ENABLED') || define('DB_ACCESS_ENABLED', false);
defined('DB_ACCESS_PWD') || define('DB_ACCESS_PWD', '');
defined('DEV_MODE') || define('DEV_MODE', false);
defined('XC_VM_VERSION') || define('XC_VM_VERSION', '2.5.2');
// Per-build watermark stamped into the deploy root by `make main` (see the
// Makefile stamp_release_id target). A source/dev checkout is never stamped, so
// runtime and the licence activation call report 'dev'. Unique per build, so a
// leaked copy can be traced back to the build it came from.
defined('XC_VM_BUILD_ID') || define('XC_VM_BUILD_ID', (
is_file(__DIR__ . '/../../RELEASE_ID')
? trim((string) file_get_contents(__DIR__ . '/../../RELEASE_ID'))
: ''
) ?: 'dev');
/**
* Single source of truth for the runtime constants that used to live in the
+7
View File
@@ -51,6 +51,13 @@ final class ConstantsInitializerTest extends TestCase {
$this->assertSame(3, $cfg['MONITOR_CALLS']);
}
public function testBuildIdWatermarkDefaultsToDevInSourceCheckout(): void {
// Loading the class defines XC_VM_BUILD_ID at file scope. `make main`
// stamps a RELEASE_ID into the deploy root; a source checkout has none.
$this->assertTrue(defined('XC_VM_BUILD_ID'));
$this->assertSame('dev', XC_VM_BUILD_ID);
}
public function testBinariesDeriveFromBinPath(): void {
$bin = ConstantsInitializer::binaries('/home/xc_vm/bin/');