Skip to content

Commit d4eeea6

Browse files
committed
chore: added some tests.
1 parent cef18e5 commit d4eeea6

File tree

10 files changed

+722
-12
lines changed

10 files changed

+722
-12
lines changed

.github/SECURITY.md

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,124 @@
22

33
## Supported Versions
44

5-
Use this section to tell people about which versions of your project are
6-
currently being supported with security updates.
5+
We take security seriously and provide security updates for the following
6+
versions:
77

88
| Version | Supported |
99
| ------- | ------------------ |
10-
| 1.0.x | :white_check_mark: |
11-
| < 0.9 | :x: |
10+
| 0.8.x | :white_check_mark: |
11+
| 0.7.x | :white_check_mark: |
12+
| < 0.7 | :x: |
1213

1314
## Reporting a Vulnerability
1415

15-
Use this section to tell people how to report a vulnerability.
16+
We greatly appreciate security research and responsible disclosure of
17+
vulnerabilities. If you discover a security vulnerability in eserstack, please
18+
report it to us promptly.
1619

17-
Tell them where to go, how often they can expect to get an update on a reported
18-
vulnerability, what to expect if the vulnerability is accepted or declined, etc.
20+
### How to Report
21+
22+
Please **DO NOT** report security vulnerabilities through public GitHub issues.
23+
Instead, use one of the following methods:
24+
25+
1. **GitHub Security Advisories** (Preferred): Use GitHub's private
26+
vulnerability reporting feature
27+
2. **Email**: Send details to
28+
29+
30+
### What to Include
31+
32+
When reporting a vulnerability, please provide:
33+
34+
- A clear description of the vulnerability
35+
- Steps to reproduce the issue
36+
- Potential impact assessment
37+
- Any suggested mitigations or fixes
38+
- Your contact information for follow-up
39+
40+
### Response Timeline
41+
42+
- **Initial Response**: We will acknowledge receipt within 48 hours
43+
- **Status Update**: We will provide a status update within 7 days
44+
- **Resolution**: We aim to resolve critical vulnerabilities within 30 days
45+
46+
### Security Best Practices
47+
48+
When using eserstack, please follow these security best practices:
49+
50+
#### Dependency Injection
51+
52+
- Validate all service factory functions
53+
- Avoid registering sensitive data directly as singleton services
54+
- Use proper error handling in service factories
55+
- Don't expose internal services through public APIs
56+
57+
#### Configuration Management
58+
59+
- Never commit sensitive configuration data to version control
60+
- Use environment variables for secrets and credentials
61+
- Validate all configuration inputs
62+
- Use secure defaults for configuration options
63+
64+
#### Parsing and Input Handling
65+
66+
- Always validate input data before processing
67+
- Use proper error boundaries to prevent information leakage
68+
- Sanitize user-provided data before parsing
69+
- Be cautious with dynamic imports and code execution
70+
71+
#### File System Operations
72+
73+
- Validate file paths to prevent directory traversal attacks
74+
- Use proper permissions and access controls
75+
- Avoid processing untrusted file contents without validation
76+
- Implement resource limits for file operations
77+
78+
## Security Features
79+
80+
eserstack includes several security features:
81+
82+
- **Input Validation**: Built-in validation for service tokens and configuration
83+
- **Error Boundaries**: Proper error handling to prevent information disclosure
84+
- **Type Safety**: Strong TypeScript typing to prevent common vulnerabilities
85+
- **Secure Defaults**: Conservative default configurations
86+
- **Dependency Isolation**: Controlled dependency injection to prevent
87+
unauthorized access
88+
89+
## Known Security Considerations
90+
91+
### Dynamic Imports
92+
93+
The collector module uses dynamic imports which could potentially be exploited
94+
if file paths are not properly validated. Always validate module paths before
95+
using the collector.
96+
97+
### Configuration Loading
98+
99+
Configuration files are loaded and parsed dynamically. Ensure configuration
100+
files come from trusted sources and validate their contents.
101+
102+
### Service Factory Functions
103+
104+
Service factory functions in the DI container execute arbitrary code. Only
105+
register trusted factory functions.
106+
107+
## Updates and Patches
108+
109+
Security updates will be:
110+
111+
- Released as patch versions for supported major versions
112+
- Announced through GitHub Security Advisories
113+
- Documented in the CHANGELOG.md with security impact noted
114+
- Tagged with appropriate CVE numbers when applicable
115+
116+
## Contact
117+
118+
For general security questions or to report non-critical security concerns, you
119+
can:
120+
121+
- Open a GitHub Discussion in the Security category
122+
- Contact the maintainers through the issue tracker
123+
- Email us at [[email protected]](mailto:[email protected])
124+
125+
Thank you for helping keep eserstack and its users safe!

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ jobs:
4646
# - windows-latest
4747
# - macOS-latest
4848
deno-version:
49-
- 2.4.4
49+
- 2.4.5
5050

5151
steps:
5252
- name: Checkout repository

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ portable across all these platforms.
143143

144144
## 🚀 Jumpstart
145145

146-
Ensure that [Deno](https://deno.land/) 1.45 or higher is installed on your
147-
system first.
146+
Ensure that [Deno](https://deno.land/) 2.4 or higher is installed on your system
147+
first.
148148

149149
First, install `cool cli` globally, then create a new project:
150150

@@ -187,7 +187,7 @@ your fork, and then submit a pull request.
187187

188188
### Requirements
189189

190-
- Deno 1.45 or higher (https://deno.land/)
190+
- Deno 2.4 or higher (https://deno.land/)
191191

192192
### Versioning
193193

deno.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/@eser/bundler/deno.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"name": "@eser/bundler",
33
"version": "0.7.20",
44
"imports": {
5+
"@std/assert": "jsr:@std/assert@^1.0.0",
56
"@std/encoding": "jsr:@std/encoding@^1.0.1",
67
"@std/fmt": "jsr:@std/fmt@^1.0.8",
78
"@std/path": "jsr:@std/path@^1.0.0",

pkg/@eser/bundler/esbuild.test.ts

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
// Copyright 2023-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license.
2+
3+
import * as assert from "@std/assert";
4+
import {
5+
createEsbuildBuilderState,
6+
EsbuildBuilder,
7+
type EsbuildBuilderOptions,
8+
} from "./esbuild.ts";
9+
10+
Deno.test("createEsbuildBuilderState() creates valid state", () => {
11+
const options: EsbuildBuilderOptions = {
12+
buildID: "test-build-123",
13+
entrypoints: {
14+
"main": "./src/main.ts",
15+
"worker": "./src/worker.ts",
16+
},
17+
dev: true,
18+
configPath: "./deno.json",
19+
target: "es2022",
20+
absoluteWorkingDir: "/project/root",
21+
jsx: "precompile",
22+
jsxImportSource: "@eser/jsx-runtime",
23+
basePath: "/static",
24+
};
25+
26+
const state = createEsbuildBuilderState(options);
27+
28+
assert.assertEquals(state.options, options);
29+
assert.assertEquals(state.options.buildID, "test-build-123");
30+
assert.assertEquals(state.options.dev, true);
31+
assert.assertEquals(state.options.target, "es2022");
32+
});
33+
34+
Deno.test("EsbuildBuilder constructor initializes with state", () => {
35+
const options: EsbuildBuilderOptions = {
36+
buildID: "test-build",
37+
entrypoints: { "main": "./main.ts" },
38+
dev: false,
39+
configPath: "./deno.json",
40+
target: "es2022",
41+
absoluteWorkingDir: "/test",
42+
};
43+
44+
const state = createEsbuildBuilderState(options);
45+
const builder = new EsbuildBuilder(state);
46+
47+
assert.assertEquals(builder.state, state);
48+
assert.assertEquals(builder.state.options.buildID, "test-build");
49+
});
50+
51+
Deno.test("EsbuildBuilderOptions supports string target", () => {
52+
const options: EsbuildBuilderOptions = {
53+
buildID: "test",
54+
entrypoints: {},
55+
dev: false,
56+
configPath: "./deno.json",
57+
target: "es2022",
58+
absoluteWorkingDir: "/test",
59+
};
60+
61+
assert.assertEquals(options.target, "es2022");
62+
});
63+
64+
Deno.test("EsbuildBuilderOptions supports array target", () => {
65+
const options: EsbuildBuilderOptions = {
66+
buildID: "test",
67+
entrypoints: {},
68+
dev: false,
69+
configPath: "./deno.json",
70+
target: ["es2022", "chrome90", "firefox88"],
71+
absoluteWorkingDir: "/test",
72+
};
73+
74+
assert.assertInstanceOf(options.target, Array);
75+
assert.assertEquals(options.target.length, 3);
76+
assert.assertEquals(options.target[0], "es2022");
77+
});
78+
79+
Deno.test("EsbuildBuilderOptions handles empty entrypoints", () => {
80+
const options: EsbuildBuilderOptions = {
81+
buildID: "test",
82+
entrypoints: {},
83+
dev: false,
84+
configPath: "./deno.json",
85+
target: "es2022",
86+
absoluteWorkingDir: "/test",
87+
};
88+
89+
const state = createEsbuildBuilderState(options);
90+
assert.assertEquals(Object.keys(state.options.entrypoints).length, 0);
91+
});
92+
93+
Deno.test("EsbuildBuilderOptions handles multiple entrypoints", () => {
94+
const entrypoints = {
95+
"main": "./src/main.ts",
96+
"admin": "./src/admin.ts",
97+
"worker": "./src/worker.ts",
98+
};
99+
100+
const options: EsbuildBuilderOptions = {
101+
buildID: "test",
102+
entrypoints,
103+
dev: false,
104+
configPath: "./deno.json",
105+
target: "es2022",
106+
absoluteWorkingDir: "/test",
107+
};
108+
109+
const state = createEsbuildBuilderState(options);
110+
assert.assertEquals(Object.keys(state.options.entrypoints).length, 3);
111+
assert.assertEquals(state.options.entrypoints["main"], "./src/main.ts");
112+
assert.assertEquals(state.options.entrypoints["admin"], "./src/admin.ts");
113+
assert.assertEquals(state.options.entrypoints["worker"], "./src/worker.ts");
114+
});
115+
116+
Deno.test("EsbuildBuilderOptions jsx configuration", () => {
117+
const options: EsbuildBuilderOptions = {
118+
buildID: "test",
119+
entrypoints: {},
120+
dev: false,
121+
configPath: "./deno.json",
122+
target: "es2022",
123+
absoluteWorkingDir: "/test",
124+
jsx: "react-jsx",
125+
jsxImportSource: "react",
126+
};
127+
128+
assert.assertEquals(options.jsx, "react-jsx");
129+
assert.assertEquals(options.jsxImportSource, "react");
130+
});
131+
132+
Deno.test("EsbuildBuilderOptions optional jsx fields", () => {
133+
const options: EsbuildBuilderOptions = {
134+
buildID: "test",
135+
entrypoints: {},
136+
dev: false,
137+
configPath: "./deno.json",
138+
target: "es2022",
139+
absoluteWorkingDir: "/test",
140+
};
141+
142+
assert.assertEquals(options.jsx, undefined);
143+
assert.assertEquals(options.jsxImportSource, undefined);
144+
});
145+
146+
Deno.test("EsbuildBuilderOptions basePath configuration", () => {
147+
const options: EsbuildBuilderOptions = {
148+
buildID: "test",
149+
entrypoints: {},
150+
dev: false,
151+
configPath: "./deno.json",
152+
target: "es2022",
153+
absoluteWorkingDir: "/test",
154+
basePath: "/static/assets",
155+
};
156+
157+
assert.assertEquals(options.basePath, "/static/assets");
158+
});
159+
160+
Deno.test("EsbuildBuilderOptions dev flag affects behavior", () => {
161+
const devOptions: EsbuildBuilderOptions = {
162+
buildID: "test",
163+
entrypoints: {},
164+
dev: true,
165+
configPath: "./deno.json",
166+
target: "es2022",
167+
absoluteWorkingDir: "/test",
168+
};
169+
170+
const prodOptions: EsbuildBuilderOptions = {
171+
buildID: "test",
172+
entrypoints: {},
173+
dev: false,
174+
configPath: "./deno.json",
175+
target: "es2022",
176+
absoluteWorkingDir: "/test",
177+
};
178+
179+
assert.assertEquals(devOptions.dev, true);
180+
assert.assertEquals(prodOptions.dev, false);
181+
});
182+
183+
Deno.test("EsbuildBuilder state is readonly", () => {
184+
const options: EsbuildBuilderOptions = {
185+
buildID: "test",
186+
entrypoints: {},
187+
dev: false,
188+
configPath: "./deno.json",
189+
target: "es2022",
190+
absoluteWorkingDir: "/test",
191+
};
192+
193+
const state = createEsbuildBuilderState(options);
194+
const builder = new EsbuildBuilder(state);
195+
196+
// Verify state is readonly by checking if it's the same reference
197+
assert.assertEquals(builder.state, state);
198+
199+
// Try to verify readonly nature (TypeScript would catch this, but test the runtime behavior)
200+
const originalState = builder.state;
201+
assert.assertEquals(builder.state, originalState);
202+
});

0 commit comments

Comments
 (0)