jarvis-ci 1.0.0 → 1.0.3
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 +231 -1
- package/configs/.jarvis-ci.json +24 -2
- package/dist/bin/cli.js +18 -1
- package/dist/commands/config/config.command.js +9 -2
- package/dist/commands/pipeline/pipeline.command.js +1 -0
- package/package.json +2 -2
- package/pipelines/asdf/asdf.jarvis.yaml +1 -0
- package/pipelines/backend/backend.jarvis.yaml +1 -0
- package/pipelines/n/n.jarvis.yaml +1 -0
package/README.md
CHANGED
|
@@ -1,5 +1,235 @@
|
|
|
1
1
|
# jarvis-ci
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
A lightweight Node.js-based CI/CD tool that executes YAML-defined pipelines on local machines or servers.
|
|
4
|
+
|
|
5
|
+
jarvis-ci is designed for simplicity, control, and self-hosted automation, similar in concept to GitHub Actions or GitLab CI, but running entirely under user-managed infrastructure.
|
|
3
6
|
|
|
4
7
|
for local machine , the user needs to configure the proxy URL from https://smee.io
|
|
5
8
|
|
|
9
|
+
https://www.npmjs.com/package/jarvis-ci
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g jarvis-ci
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Overview
|
|
22
|
+
|
|
23
|
+
jarvis-ci enables developers to define CI/CD workflows using a YAML configuration file and execute them via a webhook-driven system.
|
|
24
|
+
|
|
25
|
+
It supports:
|
|
26
|
+
|
|
27
|
+
* GitHub webhook-based triggers
|
|
28
|
+
* YAML-based pipeline definitions
|
|
29
|
+
* Local and server-based execution
|
|
30
|
+
* Working directory isolation per repository
|
|
31
|
+
* Restricted command execution for safety
|
|
32
|
+
|
|
33
|
+
For local development environments, webhook forwarding can be configured using a proxy service such as smee.io.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# Core Features
|
|
38
|
+
|
|
39
|
+
* YAML-driven pipeline execution
|
|
40
|
+
* GitHub webhook integration
|
|
41
|
+
* Multi-repository support
|
|
42
|
+
* Local and public server deployment modes
|
|
43
|
+
* Working directory isolation per pipeline
|
|
44
|
+
* Whitelisted command execution model
|
|
45
|
+
* Structured logging using Listr2
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
# Security Model
|
|
50
|
+
|
|
51
|
+
The system enforces a strict command whitelist to prevent arbitrary execution.
|
|
52
|
+
|
|
53
|
+
Allowed commands:
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
const ALLOWED_COMMANDS = [
|
|
57
|
+
"node",
|
|
58
|
+
"npm",
|
|
59
|
+
"docker",
|
|
60
|
+
"docker-compose",
|
|
61
|
+
"ssh",
|
|
62
|
+
"git"
|
|
63
|
+
];
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Each pipeline is executed in an isolated working directory to prevent cross-repository contamination.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
# Pipeline Configuration (YAML)
|
|
71
|
+
|
|
72
|
+
Each repository defines its pipeline using a `.jarvis.yml` file.
|
|
73
|
+
|
|
74
|
+
Example configuration:
|
|
75
|
+
|
|
76
|
+
```yaml
|
|
77
|
+
steps:
|
|
78
|
+
- name: Install dependencies
|
|
79
|
+
run:
|
|
80
|
+
cmd: npm
|
|
81
|
+
args: ["install"]
|
|
82
|
+
|
|
83
|
+
- name: Run tests
|
|
84
|
+
run:
|
|
85
|
+
cmd: npm
|
|
86
|
+
args: ["test"]
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
---
|
|
90
|
+
|
|
91
|
+
# CLI Commands
|
|
92
|
+
|
|
93
|
+
## Configuration
|
|
94
|
+
|
|
95
|
+
### Add repository configuration
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
jarvis config add
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Adds a new repository configuration for CI execution.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### Set webhook port
|
|
106
|
+
|
|
107
|
+
```bash
|
|
108
|
+
jarvis config port
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Defines the port on which the webhook server will run.
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### Configure server mode
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
jarvis config local
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Sets webhook server accessibility mode:
|
|
122
|
+
|
|
123
|
+
* `yes`: Localhost only
|
|
124
|
+
* `no`: Public IP accessible
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### Configure proxy mode
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
jarvis config proxy
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Enables webhook forwarding through smee.io for local development environments.
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## Runtime
|
|
139
|
+
|
|
140
|
+
### Start webhook server
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
jarvis start
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Starts the webhook listener and pipeline execution engine.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
## Pipeline Management
|
|
151
|
+
|
|
152
|
+
### List pipelines
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
jarvis pipeline list
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Displays all configured pipelines.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Delete pipeline
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
jarvis pipeline delete <pipelineName>
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Removes an existing pipeline configuration.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
### Edit pipeline
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
jarvis pipeline edit <pipelineName>
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Modifies an existing pipeline configuration.
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
# Execution Flow
|
|
183
|
+
|
|
184
|
+
The system operates as follows:
|
|
185
|
+
|
|
186
|
+
1. GitHub push event triggers webhook
|
|
187
|
+
2. Webhook server receives and validates event
|
|
188
|
+
3. Repository configuration is matched
|
|
189
|
+
4. Repository is cloned or updated in isolated directory
|
|
190
|
+
5. `.jarvis.yml` pipeline is loaded
|
|
191
|
+
6. Pipeline is validated against allowed commands
|
|
192
|
+
7. Steps are executed sequentially using Listr2
|
|
193
|
+
8. Each step runs in its isolated working directory using execa
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
# Architecture Components
|
|
198
|
+
|
|
199
|
+
* YAML parser for pipeline definitions
|
|
200
|
+
* Validation layer enforcing command restrictions
|
|
201
|
+
* Execution engine using execa for process control
|
|
202
|
+
* Task runner using Listr2 for structured output
|
|
203
|
+
* Webhook handler based on @octokit/webhooks
|
|
204
|
+
* Repository workspace isolation layer
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
# Development Mode (Local Setup)
|
|
209
|
+
|
|
210
|
+
For local environments, webhook events can be forwarded using a proxy such as smee.io.
|
|
211
|
+
|
|
212
|
+
This allows GitHub webhooks to reach a locally running jarvis-ci instance.
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
# Design Principles
|
|
217
|
+
|
|
218
|
+
* Minimal configuration overhead
|
|
219
|
+
* Deterministic pipeline execution
|
|
220
|
+
* Secure command execution model
|
|
221
|
+
* Isolation per repository workspace
|
|
222
|
+
* Predictable and traceable CI behavior
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
# Future Improvements
|
|
227
|
+
|
|
228
|
+
* Containerized execution per pipeline
|
|
229
|
+
* Parallel pipeline execution engine
|
|
230
|
+
* Artifact storage system
|
|
231
|
+
* Retry and failure policy system
|
|
232
|
+
* Plugin-based step extensions
|
|
233
|
+
* Remote dashboard for pipeline monitoring
|
|
234
|
+
|
|
235
|
+
---
|
package/configs/.jarvis-ci.json
CHANGED
|
@@ -3,7 +3,29 @@
|
|
|
3
3
|
"port": 5050,
|
|
4
4
|
"local": false,
|
|
5
5
|
"proxy": "",
|
|
6
|
-
"secret": ""
|
|
6
|
+
"secret": "6e23a467d3acbf3adb29979f1757876d"
|
|
7
7
|
},
|
|
8
|
-
"repos": [
|
|
8
|
+
"repos": [
|
|
9
|
+
{
|
|
10
|
+
"name": "backend",
|
|
11
|
+
"repo": "asdf/sdf",
|
|
12
|
+
"branch": "main",
|
|
13
|
+
"yamlPath": "/home/muqeet-ahmad/Desktop/jarvis-ci/pipelines/backend/backend.jarvis.yaml",
|
|
14
|
+
"tempDir": "/home/muqeet-ahmad/Desktop/jarvis-ci/tmp/asdf-sdf"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"name": "n",
|
|
18
|
+
"repo": "sdf/sdf",
|
|
19
|
+
"branch": "main",
|
|
20
|
+
"yamlPath": "/home/muqeet-ahmad/Desktop/jarvis-ci/pipelines/n/n.jarvis.yaml",
|
|
21
|
+
"tempDir": "/home/muqeet-ahmad/Desktop/jarvis-ci/tmp/sdf-sdf"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "asdf",
|
|
25
|
+
"repo": "sd/d",
|
|
26
|
+
"branch": "main",
|
|
27
|
+
"yamlPath": "/home/muqeet-ahmad/Desktop/jarvis-ci/pipelines/asdf/asdf.jarvis.yaml",
|
|
28
|
+
"tempDir": "/home/muqeet-ahmad/Desktop/jarvis-ci/tmp/sd-d"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
9
31
|
}
|
package/dist/bin/cli.js
CHANGED
|
@@ -1,14 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import path from "path";
|
|
2
3
|
import { ConfigCommand } from "../commands/config/config.command.js";
|
|
3
4
|
import { PipelineCommand } from "../commands/pipeline/pipeline.command.js";
|
|
4
5
|
import { ServerCommand } from "../commands/server/server.command.js";
|
|
5
6
|
import { Server } from "../server.js";
|
|
7
|
+
import fs from 'fs';
|
|
6
8
|
export class JarvisCLI {
|
|
7
9
|
static instance;
|
|
8
10
|
configCommand;
|
|
9
11
|
serverCommand;
|
|
10
12
|
PipelineCommand;
|
|
13
|
+
CONFIG_PATH = path.join(process.cwd(), 'configs');
|
|
14
|
+
baseConfiguration = {
|
|
15
|
+
"server": {
|
|
16
|
+
"port": 5050,
|
|
17
|
+
"local": false,
|
|
18
|
+
"proxy": "",
|
|
19
|
+
"secret": ""
|
|
20
|
+
},
|
|
21
|
+
"repos": []
|
|
22
|
+
};
|
|
11
23
|
constructor() {
|
|
24
|
+
if (!fs.existsSync(this.CONFIG_PATH)) {
|
|
25
|
+
fs.mkdirSync(this.CONFIG_PATH, { recursive: true });
|
|
26
|
+
fs.writeFileSync(path.join(this.CONFIG_PATH, '.jarvis-ci.json'), JSON.stringify(this.baseConfiguration));
|
|
27
|
+
}
|
|
12
28
|
this.configCommand = new ConfigCommand();
|
|
13
29
|
this.serverCommand = new ServerCommand();
|
|
14
30
|
this.PipelineCommand = new PipelineCommand();
|
|
@@ -61,7 +77,6 @@ export class JarvisCLI {
|
|
|
61
77
|
return;
|
|
62
78
|
}
|
|
63
79
|
switch (subcommand) {
|
|
64
|
-
case 'add':
|
|
65
80
|
case 'edit':
|
|
66
81
|
this.PipelineCommand.editPipeline(pipelineName);
|
|
67
82
|
break;
|
|
@@ -83,6 +98,8 @@ Jarvis CLI
|
|
|
83
98
|
Commands:
|
|
84
99
|
jarvis config add Add repository configuration
|
|
85
100
|
jarvis config port Set webhook server port
|
|
101
|
+
jarvis config local Set webhook server to listen on localhost(yes) or public ip enabled server (no)
|
|
102
|
+
jarvis config proxy Set webhook server to listen on interfaces (proxy mode) from smee.io
|
|
86
103
|
jarvis start Start webhook server
|
|
87
104
|
jarvis pipeline list List all pipelines
|
|
88
105
|
jarvis pipeline delete <pipelineName> Delete a pipeline configuration
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { ConfigService } from './config.service.js';
|
|
4
|
+
import crypto from 'crypto';
|
|
4
5
|
export class ConfigCommand {
|
|
5
6
|
CONFIG_PATH = path.join(process.cwd(), 'configs', '.jarvis-ci.json');
|
|
6
7
|
configService;
|
|
@@ -12,7 +13,7 @@ export class ConfigCommand {
|
|
|
12
13
|
const proxyURL = local ? (await this.configService.getProxyURL()).proxy : '';
|
|
13
14
|
const { githubRepoURL } = await this.configService.getGithubRepo();
|
|
14
15
|
const { branchName } = await this.configService.getBranchName();
|
|
15
|
-
const { webhookSecret } = await this.configService.getWebhookSecret()
|
|
16
|
+
// const { webhookSecret } = await this.configService.getWebhookSecret()
|
|
16
17
|
const { pipelineName } = await this.configService.getPipelineName();
|
|
17
18
|
const tempDirPath = this.configService.createTempPipelineDirectory(githubRepoURL);
|
|
18
19
|
if (!tempDirPath) {
|
|
@@ -33,13 +34,19 @@ export class ConfigCommand {
|
|
|
33
34
|
};
|
|
34
35
|
const configFile = fs.readFileSync(this.CONFIG_PATH);
|
|
35
36
|
let configArray = JSON.parse(configFile.toString());
|
|
36
|
-
configArray.server.secret
|
|
37
|
+
const webhookSecret = configArray.server.secret !== "" ? configArray.server.secret : crypto.randomBytes(16).toString('hex');
|
|
38
|
+
if (configArray.server.secret !== "") {
|
|
39
|
+
configArray.server.secret = webhookSecret;
|
|
40
|
+
}
|
|
37
41
|
configArray.server.local = local;
|
|
38
42
|
if (local) {
|
|
39
43
|
configArray.server.proxy = proxyURL;
|
|
40
44
|
}
|
|
41
45
|
configArray.repos.push(config);
|
|
42
46
|
fs.writeFileSync(this.CONFIG_PATH, JSON.stringify(configArray, null, 2));
|
|
47
|
+
console.info(`
|
|
48
|
+
The webhook secret is this: ${webhookSecret}
|
|
49
|
+
`);
|
|
43
50
|
console.log('✅ configuration has been added successfully to .jarvis-ci.json');
|
|
44
51
|
}
|
|
45
52
|
loadConfig() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jarvis-ci",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "This npm package is light weight CI/CD tool. the goal is to achieve simplicity and local machine CI/CD execution. it is configured through YAML for commands.",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -51,4 +51,4 @@
|
|
|
51
51
|
"esbuild": "^0.27.4",
|
|
52
52
|
"typescript": "^6.0.2"
|
|
53
53
|
}
|
|
54
|
-
}
|
|
54
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sdfg
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
asdfsdf
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
ljk
|