@m14i/sith 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,44 +10,59 @@ Standardize and share your OpenCode setup with a fully dockerized environment, d
10
10
 
11
11
  ## Usage
12
12
 
13
- No installation required! Run with npx:
13
+ ### Quick Start
14
14
 
15
15
  ```bash
16
+ # Interactive menu (recommended)
16
17
  npx @m14i/sith
17
- ```
18
18
 
19
- ### Interactive Menu (Default)
19
+ # Pull prebuilt image directly
20
+ npx @m14i/sith --pull
20
21
 
21
- ```bash
22
- npx @m14i/sith
22
+ # Run shell
23
+ npx @m14i/sith shell
23
24
  ```
24
25
 
25
- This will present you with options to:
26
- - 🔨 Build Docker image
26
+ ### Distribution Options
27
27
 
28
- ### Quick Build
28
+ | Method | Command | Speed | Trust Model | Use Case |
29
+ |--------|---------|-------|-------------|----------|
30
+ | **Prebuilt (Recommended)** | `npx @m14i/sith --pull` | ⚡ Fast | GitHub Actions + Cosign | Production, CI/CD |
31
+ | **Local Build** | `npx @m14i/sith --build` | 🐌 Slow | Your machine | Air-gapped, custom builds |
29
32
 
30
- Build the Docker image directly:
33
+ ### Commands
31
34
 
32
- ```bash
33
- npx @m14i/sith docker --build
34
- # or
35
- npx @m14i/sith --build
36
- ```
35
+ | Command | Description |
36
+ |---------|-------------|
37
+ | `npx @m14i/sith` | Interactive menu with options |
38
+ | `npx @m14i/sith --pull` | Pull prebuilt image from GHCR |
39
+ | `npx @m14i/sith --build` | Build Docker image from scratch |
40
+ | `npx @m14i/sith shell` | Launch interactive shell in container |
41
+ | `npx @m14i/sith --help` | Show all available commands |
37
42
 
38
- ### Interactive Shell
39
-
40
- Run an interactive shell in the Docker container:
43
+ ### Prebuilt Image Details
41
44
 
45
+ **Pull and verify:**
42
46
  ```bash
43
- npx @m14i/sith shell
47
+ # Pull (supports linux/amd64 and linux/arm64)
48
+ npx @m14i/sith --pull
49
+
50
+ # Or use Docker directly
51
+ docker pull ghcr.io/merzoukemanouri/sith:latest
52
+
53
+ # Verify signature (optional)
54
+ cosign verify \
55
+ --certificate-identity-regexp="https://github.com/MerzoukeMansouri/sith" \
56
+ --certificate-oidc-issuer="https://token.actions.githubusercontent.com" \
57
+ ghcr.io/merzoukemanouri/sith:latest
44
58
  ```
45
59
 
46
- This will:
47
- - Mount current directory to `/workspace`
48
- - Load full Nix environment with all tools
49
- - Make OpenCode CLI available
50
- - Pass your `GITHUB_TOKEN` environment variable
60
+ **Benefits:**
61
+ - Fast - no build time
62
+ - Multi-platform - amd64 and arm64
63
+ - Signed - cosign verification
64
+ - SBOM - supply chain transparency
65
+ - ✅ Auto-updated - tracks releases
51
66
 
52
67
  ## Authentication
53
68
 
@@ -78,24 +93,44 @@ npx @m14i/sith shell
78
93
  export GITHUB_TOKEN=$(gh auth token)
79
94
  ```
80
95
 
81
- ## Commands
82
-
83
- ### `npx @m14i/sith` (default)
84
- Launches the interactive menu.
85
-
86
- ### `npx @m14i/sith docker --build`
87
- Build the Docker image.
88
-
89
- ### `npx @m14i/sith shell`
90
- Run interactive shell in the Docker container.
91
-
92
96
  ## Features
93
97
 
98
+ - **Prebuilt Images**: Pull verified images from GitHub Container Registry
99
+ - **Image Signing**: All images signed with cosign for supply chain security
100
+ - **SBOM Attestation**: Software Bill of Materials included with every image
94
101
  - **Interactive Menu**: Navigate with arrow keys, select with Enter
95
102
  - **Direct Commands**: Build or shell access without menu
96
103
  - **Dockerized Environment**: Consistent setup across machines
97
104
  - **Nix Integration**: Full development environment with all tools
98
105
  - **CI-Ready**: Standardize builds across local and CI pipelines
106
+ - **Non-root User**: Images run as non-root user (UID 1000) for better security
107
+
108
+ ## Security
109
+
110
+ ### Image Verification
111
+
112
+ All Docker images published to `ghcr.io/merzoukemanouri/sith` are:
113
+ - **Signed with cosign** using keyless signing (OIDC)
114
+ - **Include SBOM** (Software Bill of Materials) for transparency
115
+ - **Built automatically** via GitHub Actions with provenance
116
+
117
+ See [SECURITY.md](./SECURITY.md) for detailed security practices and considerations.
118
+
119
+ ### Trust Model
120
+
121
+ **Prebuilt Images:**
122
+ - Built by GitHub Actions on public infrastructure
123
+ - Signed with Sigstore keyless signing
124
+ - Verifiable provenance chain from source to image
125
+ - Trade-off: Trust GitHub's build infrastructure
126
+
127
+ **Local Builds:**
128
+ - Full control over build environment
129
+ - Can inspect Dockerfile before building
130
+ - No dependency on external registries
131
+ - Trade-off: Slower, manual security updates
132
+
133
+ For more details, see the [Docker Distribution Guide](./doc/QUICKSTART.md#docker-distribution).
99
134
 
100
135
  ## Development
101
136
 
@@ -1 +1 @@
1
- {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/commands/docker.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAkC,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAoNxF,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAehF;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD"}
1
+ {"version":3,"file":"docker.d.ts","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/commands/docker.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAkC,oBAAoB,EAAE,MAAM,aAAa,CAAC;AA6PxF,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC,CAoBhF;AAED,wBAAsB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAEpD"}
package/dist/config.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export declare const DOCKER_CONFIG: {
2
2
  readonly imageName: "opencode-ci:latest";
3
+ readonly prebuiltImage: "ghcr.io/merzoukemanouri/sith:latest";
3
4
  readonly folderName: "docker";
4
5
  readonly dockerfileName: "Dockerfile";
5
6
  readonly workspaceMount: "/workspace";
@@ -1 +1 @@
1
- {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/config.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa;;;;;;CAMhB,CAAC;AAGX,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAGX,eAAO,MAAM,UAAU,mOAOb,CAAC"}
1
+ {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/config.ts"],"names":[],"mappings":"AACA,eAAO,MAAM,aAAa;;;;;;;CAOhB,CAAC;AAGX,eAAO,MAAM,cAAc;;;CAGjB,CAAC;AAGX,eAAO,MAAM,UAAU,mOAOb,CAAC"}
package/dist/index.js CHANGED
@@ -35471,7 +35471,8 @@ function findProjectRoot(startDir) {
35471
35471
  }
35472
35472
  const rootDir = findProjectRoot(__dirname);
35473
35473
  const menuItems = [
35474
- { label: "Build Docker image", value: "build", icon: "🔨" },
35474
+ { label: "Pull prebuilt image (recommended)", value: "pull", icon: "📦" },
35475
+ { label: "Build Docker image from scratch", value: "build", icon: "🔨" },
35475
35476
  { label: "Exit", value: "exit", icon: "❌" },
35476
35477
  ];
35477
35478
  function Logo() {
@@ -35497,16 +35498,16 @@ function BuildingSpinner({ step }) {
35497
35498
  function Menu() {
35498
35499
  const { exit } = (0,ink__WEBPACK_IMPORTED_MODULE_1__/* .useApp */ .nm)();
35499
35500
  const [selectedIndex, setSelectedIndex] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(0);
35500
- const [isBuilding, setIsBuilding] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
35501
- const [buildStep, setBuildStep] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)("");
35502
- const [buildComplete, setBuildComplete] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
35503
- const [buildError, setBuildError] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
35501
+ const [isProcessing, setIsProcessing] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
35502
+ const [processStep, setProcessStep] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)("");
35503
+ const [processComplete, setProcessComplete] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(false);
35504
+ const [processError, setProcessError] = (0,react__WEBPACK_IMPORTED_MODULE_0__.useState)(null);
35504
35505
  (0,ink__WEBPACK_IMPORTED_MODULE_1__/* .useInput */ .Ge)((_input, key) => {
35505
- if (isBuilding) {
35506
+ if (isProcessing) {
35506
35507
  return;
35507
35508
  }
35508
- // Exit on any key press when build is complete or errored
35509
- if (buildComplete || buildError) {
35509
+ // Exit on any key press when process is complete or errored
35510
+ if (processComplete || processError) {
35510
35511
  exit();
35511
35512
  return;
35512
35513
  }
@@ -35525,6 +35526,9 @@ function Menu() {
35525
35526
  case "exit":
35526
35527
  exit();
35527
35528
  return;
35529
+ case "pull":
35530
+ await handlePullCommand();
35531
+ break;
35528
35532
  case "build":
35529
35533
  await handleBuildCommand();
35530
35534
  break;
@@ -35532,9 +35536,29 @@ function Menu() {
35532
35536
  break;
35533
35537
  }
35534
35538
  }
35539
+ async function handlePullCommand() {
35540
+ setIsProcessing(true);
35541
+ setProcessStep("Pulling prebuilt Docker image...");
35542
+ try {
35543
+ await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["pull", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage], {
35544
+ stdio: "inherit",
35545
+ });
35546
+ // Tag the pulled image with local name for compatibility
35547
+ await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["tag", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName], {
35548
+ stdio: "inherit",
35549
+ });
35550
+ setIsProcessing(false);
35551
+ setProcessComplete(true);
35552
+ setProcessStep("");
35553
+ }
35554
+ catch (error) {
35555
+ setIsProcessing(false);
35556
+ setProcessError(error instanceof Error ? error.message : "Pull failed");
35557
+ }
35558
+ }
35535
35559
  async function handleBuildCommand() {
35536
- setIsBuilding(true);
35537
- setBuildStep("Building Docker image...");
35560
+ setIsProcessing(true);
35561
+ setProcessStep("Building Docker image from scratch...");
35538
35562
  try {
35539
35563
  const dockerfilePath = path__WEBPACK_IMPORTED_MODULE_3___default().join(rootDir, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.dockerfileName);
35540
35564
  if (!fs__WEBPACK_IMPORTED_MODULE_2___default().existsSync(dockerfilePath)) {
@@ -35543,44 +35567,46 @@ function Menu() {
35543
35567
  await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["build", "-f", dockerfilePath, "-t", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName, rootDir], {
35544
35568
  stdio: "inherit",
35545
35569
  });
35546
- setIsBuilding(false);
35547
- setBuildComplete(true);
35548
- setBuildStep("");
35570
+ setIsProcessing(false);
35571
+ setProcessComplete(true);
35572
+ setProcessStep("");
35549
35573
  }
35550
35574
  catch (error) {
35551
- setIsBuilding(false);
35552
- setBuildError(error instanceof Error ? error.message : "Build failed");
35575
+ setIsProcessing(false);
35576
+ setProcessError(error instanceof Error ? error.message : "Operation failed");
35553
35577
  }
35554
35578
  }
35555
35579
  // Render error state
35556
- if (buildError) {
35580
+ if (processError) {
35557
35581
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column" },
35558
35582
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(Logo, null),
35559
35583
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
35560
35584
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "red" },
35561
- "\u274C Build failed: ",
35562
- buildError)),
35585
+ "\u274C Operation failed: ",
35586
+ processError)),
35563
35587
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
35564
35588
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "Press any key to exit..."))));
35565
35589
  }
35566
35590
  // Render success state
35567
- if (buildComplete) {
35591
+ if (processComplete) {
35568
35592
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column" },
35569
35593
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(Logo, null),
35570
35594
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
35571
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "green" }, "\u2705 Docker image built successfully!")),
35595
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { color: "green" }, "\u2705 Docker image ready!")),
35572
35596
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
35573
35597
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true },
35574
35598
  "Image: ",
35575
35599
  _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName)),
35600
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
35601
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "Run: npx @m14i/sith shell")),
35576
35602
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
35577
35603
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true }, "Press any key to exit..."))));
35578
35604
  }
35579
- // Render building state
35580
- if (isBuilding) {
35605
+ // Render processing state
35606
+ if (isProcessing) {
35581
35607
  return (react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { flexDirection: "column" },
35582
35608
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(Logo, null),
35583
- react__WEBPACK_IMPORTED_MODULE_0___default().createElement(BuildingSpinner, { step: buildStep }),
35609
+ react__WEBPACK_IMPORTED_MODULE_0___default().createElement(BuildingSpinner, { step: processStep }),
35584
35610
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Box */ .az, { marginTop: 1 },
35585
35611
  react__WEBPACK_IMPORTED_MODULE_0___default().createElement(ink__WEBPACK_IMPORTED_MODULE_1__/* .Text */ .EY, { dimColor: true },
35586
35612
  "Root: ",
@@ -35608,10 +35634,14 @@ async function dockerCommand(options) {
35608
35634
  await buildDocker();
35609
35635
  return;
35610
35636
  }
35637
+ if (options.pull) {
35638
+ await pullDocker();
35639
+ return;
35640
+ }
35611
35641
  // Check if stdin supports raw mode (interactive terminal)
35612
35642
  if (!process.stdin.isTTY) {
35613
35643
  console.error("Error: Interactive mode requires a TTY terminal");
35614
- console.error("Use --build flag for non-interactive mode");
35644
+ console.error("Use --build or --pull flag for non-interactive mode");
35615
35645
  process.exit(1);
35616
35646
  }
35617
35647
  // Render the interactive menu
@@ -35620,8 +35650,37 @@ async function dockerCommand(options) {
35620
35650
  async function runShellDirect() {
35621
35651
  await runShell();
35622
35652
  }
35653
+ async function pullDocker() {
35654
+ console.log("📦 Pulling prebuilt Docker image...");
35655
+ console.log();
35656
+ try {
35657
+ console.log(`Source: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage}`);
35658
+ console.log(`Target: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`);
35659
+ console.log();
35660
+ await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["pull", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage], {
35661
+ stdio: "inherit",
35662
+ });
35663
+ console.log();
35664
+ console.log("🏷️ Tagging image for local use...");
35665
+ await (0,execa__WEBPACK_IMPORTED_MODULE_6__/* .execa */ .Ho)("docker", ["tag", _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.prebuiltImage, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName], {
35666
+ stdio: "inherit",
35667
+ });
35668
+ console.log();
35669
+ console.log("✅ Docker image ready!");
35670
+ console.log(`Image: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`);
35671
+ console.log();
35672
+ console.log("Run: npx @m14i/sith shell");
35673
+ }
35674
+ catch (error) {
35675
+ console.error("❌ Pull failed");
35676
+ if (error instanceof Error) {
35677
+ console.error(error.message);
35678
+ }
35679
+ process.exit(1);
35680
+ }
35681
+ }
35623
35682
  async function buildDocker() {
35624
- console.log("🔨 Building Docker image...");
35683
+ console.log("🔨 Building Docker image from scratch...");
35625
35684
  console.log();
35626
35685
  try {
35627
35686
  const dockerfilePath = path__WEBPACK_IMPORTED_MODULE_3___default().join(rootDir, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.folderName, _config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.dockerfileName);
@@ -35637,6 +35696,8 @@ async function buildDocker() {
35637
35696
  console.log();
35638
35697
  console.log("✅ Docker image built successfully!");
35639
35698
  console.log(`Image: ${_config_js__WEBPACK_IMPORTED_MODULE_5__/* .DOCKER_CONFIG */ .e6.imageName}`);
35699
+ console.log();
35700
+ console.log("Run: npx @m14i/sith shell");
35640
35701
  }
35641
35702
  catch (error) {
35642
35703
  console.error("❌ Build failed");
@@ -35694,6 +35755,7 @@ __webpack_async_result__();
35694
35755
  // Docker configuration
35695
35756
  const DOCKER_CONFIG = {
35696
35757
  imageName: "opencode-ci:latest",
35758
+ prebuiltImage: "ghcr.io/merzoukemanouri/sith:latest",
35697
35759
  folderName: "docker",
35698
35760
  dockerfileName: "Dockerfile",
35699
35761
  workspaceMount: "/workspace",
@@ -35736,7 +35798,8 @@ function createProgram() {
35736
35798
  .name(PROGRAM_NAME)
35737
35799
  .description(PROGRAM_DESCRIPTION)
35738
35800
  .version(PROGRAM_VERSION)
35739
- .option('--build', 'Build the Docker image');
35801
+ .option('--pull', 'Pull prebuilt Docker image (recommended)')
35802
+ .option('--build', 'Build the Docker image from scratch');
35740
35803
  // Default action - show interactive menu
35741
35804
  program
35742
35805
  .action(async (options) => {
@@ -35746,7 +35809,8 @@ function createProgram() {
35746
35809
  program
35747
35810
  .command('docker')
35748
35811
  .description('Manage Docker environment')
35749
- .option('--build', 'Build the Docker image')
35812
+ .option('--pull', 'Pull prebuilt Docker image (recommended)')
35813
+ .option('--build', 'Build the Docker image from scratch')
35750
35814
  .action(async (options) => {
35751
35815
  await (0,_commands_docker_js__WEBPACK_IMPORTED_MODULE_1__/* .dockerCommand */ .Q)(options);
35752
35816
  });
package/dist/types.d.ts CHANGED
@@ -8,4 +8,5 @@ export interface BuildingSpinnerProps {
8
8
  }
9
9
  export interface DockerCommandOptions {
10
10
  build?: boolean;
11
+ pull?: boolean;
11
12
  }
@@ -1 +1 @@
1
- {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB"}
1
+ {"version":3,"file":"","sourceRoot":"","sources":["file:///home/runner/work/sith/sith/src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB"}
package/docker/Dockerfile CHANGED
@@ -1,19 +1,16 @@
1
1
  # OpenCode Docker - Nix-based Image with Token Optimization Skills
2
- # Version 2.2.0 - Ajout RTK + Caveman ultra pour réduction massive de tokens
3
- #
2
+ # Version 2.3.0 - Multi-stage build with non-root user and improved security
3
+ #
4
4
  # Build: docker build -t opencode-ci:latest .
5
5
  # Run: docker run -v $(pwd):/workspace -e GITHUB_TOKEN=$GITHUB_TOKEN opencode-ci:latest analyze
6
6
 
7
- # Utilise l'image officielle Nix avec version pinnée pour reproductibilité
8
- FROM nixos/nix:2.19.2
9
-
10
- # Metadata
11
- LABEL maintainer="OpenCode Automation"
12
- LABEL description="OpenCode CI/CD avec Nix, GitHub Copilot et skills d'optimisation de tokens (RTK + Caveman ultra)"
13
- LABEL version="2.2.0"
14
- LABEL org.opencontainers.image.source="https://github.com/your-repo/opencode-docker"
7
+ # ============================================================================
8
+ # Stage 1: Builder - Setup environment and install dependencies
9
+ # ============================================================================
10
+ FROM nixos/nix:2.19.2 AS builder
15
11
 
16
12
  # Configuration Nix pour permettre les builds
13
+ # Note: sandbox=false required for Docker-in-Docker compatibility
17
14
  RUN echo "sandbox = false" >> /etc/nix/nix.conf && \
18
15
  echo "filter-syscalls = false" >> /etc/nix/nix.conf
19
16
 
@@ -38,12 +35,47 @@ RUN nix-shell /opt/sith/nix/shell.nix --run " \
38
35
  /root/.opencode/bin/opencode --version \
39
36
  "
40
37
 
38
+ # ============================================================================
39
+ # Stage 2: Runtime - Minimal runtime image with non-root user
40
+ # ============================================================================
41
+ FROM nixos/nix:2.19.2
42
+
43
+ # Metadata
44
+ LABEL maintainer="OpenCode Automation"
45
+ LABEL description="OpenCode CI/CD avec Nix, GitHub Copilot et skills d'optimisation de tokens (RTK + Caveman ultra)"
46
+ LABEL version="2.3.0"
47
+ LABEL org.opencontainers.image.source="https://github.com/MerzoukeMansouri/sith"
48
+
49
+ # Configuration Nix pour permettre les builds
50
+ # Note: sandbox=false required for Docker-in-Docker compatibility
51
+ RUN echo "sandbox = false" >> /etc/nix/nix.conf && \
52
+ echo "filter-syscalls = false" >> /etc/nix/nix.conf
53
+
54
+ # Copier les fichiers de configuration des skills depuis builder
55
+ COPY --from=builder /opt/sith/ /opt/sith/
56
+
57
+ # Copier les binaires et configuration Nix depuis builder
58
+ COPY --from=builder /nix/store /nix/store
59
+ COPY --from=builder /root/.opencode /root/.opencode
60
+ COPY --from=builder /root/.npmrc /root/.npmrc
61
+
62
+ # Créer un utilisateur non-root pour l'exécution
63
+ RUN adduser -D -u 1000 -s /bin/sh sith && \
64
+ mkdir -p /home/sith/.opencode /home/sith/.npm-global /workspace && \
65
+ cp -r /root/.opencode/* /home/sith/.opencode/ 2>/dev/null || true && \
66
+ chown -R sith:sith /home/sith /workspace /opt/sith
67
+
68
+ # Copier la configuration npm pour l'utilisateur sith
69
+ RUN echo "registry=https://registry.npmjs.org/" > /home/sith/.npmrc && \
70
+ chown sith:sith /home/sith/.npmrc
71
+
41
72
  # Configuration de l'environnement
42
73
  ENV OPENCODE_MODEL=github-copilot/claude-sonnet-4.5
43
74
  ENV OPENCODE_LOG_LEVEL=INFO
44
75
  ENV NODE_ENV=production
45
- ENV PATH="/root/.local/bin:/root/.npm-global/bin:${PATH}"
46
- ENV NPM_CONFIG_PREFIX=/root/.npm-global
76
+ ENV PATH="/home/sith/.opencode/bin:/home/sith/.local/bin:/home/sith/.npm-global/bin:${PATH}"
77
+ ENV NPM_CONFIG_PREFIX=/home/sith/.npm-global
78
+ ENV HOME=/home/sith
47
79
 
48
80
  # === Token Optimization Skills Configuration ===
49
81
  # RTK (Rust Token Killer) - Désactivé par défaut (binaire non disponible publiquement)
@@ -56,9 +88,13 @@ ENV CAVEMAN_AUTO=true
56
88
 
57
89
  # Réduction totale estimée: 85-95% de tokens par session CI/CD
58
90
 
59
- # Healthcheck pour vérifier que l'environnement et skills sont prêts
91
+ # Basculer vers l'utilisateur non-root
92
+ USER sith
93
+
94
+ # Healthcheck pour vérifier que l'environnement est prêt
95
+ # Note: RTK check is conditional on RTK_ENABLED to avoid false failures
60
96
  HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \
61
- CMD nix-shell /opt/sith/nix/shell.nix --run "opencode --version && command -v rtk" || exit 1
97
+ CMD nix-shell /opt/sith/nix/shell.nix --run "opencode --version && ([ \"\$RTK_ENABLED\" = \"false\" ] || command -v rtk)" || exit 1
62
98
 
63
99
  # Répertoire de travail pour les projets
64
100
  WORKDIR /workspace
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@m14i/sith",
3
- "version": "1.6.0",
3
+ "version": "1.7.0",
4
4
  "description": "Turn your context to the dark side. Standardize and share your OpenCode setup with a fully dockerized environment, designed for seamless collaboration and CI integration.",
5
5
  "type": "module",
6
6
  "repository": {