Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
name: Bug Report
about: Report a bug to help us improve Dequel
title: "[Bug]: "
labels: bug, triage
assignees: ""
---

## Description

A clear and concise description of what the bug is.

## Steps to Reproduce

1. Go to '...'
2. Click on '...'
3. Scroll down to '...'
4. See error

## Expected Behavior

What did you expect to happen?

## Actual Behavior

What actually happened?

## Screenshots / Logs

If applicable, add screenshots or relevant logs.

## Environment

- **Dequel Version**: (check `VERSION` or `scripts/dequel status`)
- **OS**:
- **Docker version**:
- **Bun version** (if relevant):
- **Browser** (if relevant):

## Affected Component

- [ ] API (Backend)
- [ ] Web Dashboard (Frontend)
- [ ] Docs
- [ ] CLI / Install Script
- [ ] Docker / Deployment
- [ ] Build System (Railpack / BuildKit)
- [ ] Caddy / Ingress
- [ ] Monitoring (Prometheus / Grafana / Loki)

## Additional Context

Add any other context, workarounds, or related issues.
41 changes: 41 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
name: Feature Request
about: Suggest an idea for Dequel
title: "[Feature]: "
labels: enhancement
assignees: ""
---

## Problem Statement

Is your feature request related to a problem? Please describe what you're trying to solve.

## Proposed Solution

A clear and concise description of what you want to happen.

## Alternative Solutions

Any alternative solutions or features you've considered.

## Affected Component

- [ ] API (Backend)
- [ ] Web Dashboard (Frontend)
- [ ] Docs
- [ ] CLI / Install Script
- [ ] Build System (Railpack / BuildKit)
- [ ] Caddy / Ingress
- [ ] Monitoring (Prometheus / Grafana / Loki)

## Mockups / Examples

If applicable, add mockups, diagrams, or examples from other projects.

## Additional Context

Add any other context or screenshots.

## Would you like to implement this?

- [ ] Yes, I'd be happy to submit a PR
43 changes: 43 additions & 0 deletions .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
## Description

Please provide a summary of the changes and the motivation behind them. What problem does this PR solve?

Fixes #(issue)

## Type of Change

- [ ] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Refactor (no functional changes)
- [ ] CI / Build / Tooling
- [ ] Other (please describe):

## How Has This Been Tested?

Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce.

- [ ] Existing tests pass (`bun test` in `apps/api/`)
- [ ] New tests added (if applicable)
- [ ] Manual testing performed (describe steps)

## Checklist

- [ ] My code follows the project's code style (no comments, named exports, functional components, etc.)
- [ ] I have read the [contributing guidelines](../CONTRIBUTING.md)
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] I have updated the documentation (if applicable)
- [ ] My changes generate no new warnings or lint errors
- [ ] I have run `bun test` in `apps/api/` and all tests pass
- [ ] I have synced the VERSION file if needed (`bun run sync-versions`)

## Screenshots (if applicable)

| Before | After |
|--------|-------|
| (insert here) | (insert here) |

## Additional Context

Add any other context about the PR here (e.g., migration notes, deployment considerations, rollback strategy).
6 changes: 1 addition & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,7 @@ jobs:
cp docker-compose.yml "$TAR_DIR/"
cp scripts/dequel "$TAR_DIR/dequel"
cp infra/caddy/Caddyfile "$TAR_DIR/infra/caddy/"
cp infra/monitoring/prometheus.yml "$TAR_DIR/infra/monitoring/"
cp infra/monitoring/loki-config.yml "$TAR_DIR/infra/monitoring/"
cp infra/monitoring/promtail-config.yml "$TAR_DIR/infra/monitoring/"
cp infra/monitoring/grafana/datasources/loki.yml "$TAR_DIR/infra/monitoring/grafana/datasources/"
cp infra/monitoring/grafana/datasources/prometheus.yml "$TAR_DIR/infra/monitoring/grafana/datasources/"
cp -r infra/monitoring "$TAR_DIR/infra/"
cd "$TAR_DIR" && tar -czf "../dequel-config-${VERSION}.tar.gz" .

- name: Create GitHub Release
Expand Down
42 changes: 42 additions & 0 deletions .github/workflows/vuln-scan.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Security Scans

on:
push:
pull_request:
workflow_dispatch:

concurrency:
group: security-scans-${{ github.ref }}
cancel-in-progress: true

Comment on lines +1 to +11

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add explicit minimal permissions for least-privilege security.

The workflow runs with default write-all permissions, but a read-only scan only requires contents: read. Explicit permissions also protect against future credential leakage if steps are added.

🛡️ Proposed fix to add permissions block
 name: Security Scans

 on:
     push:
     pull_request:
     workflow_dispatch:

+permissions:
+    contents: read
+
 concurrency:
     group: security-scans-${{ github.ref }}
     cancel-in-progress: true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
name: Security Scans
on:
push:
pull_request:
workflow_dispatch:
concurrency:
group: security-scans-${{ github.ref }}
cancel-in-progress: true
name: Security Scans
on:
push:
pull_request:
workflow_dispatch:
permissions:
contents: read
concurrency:
group: security-scans-${{ github.ref }}
cancel-in-progress: true
🧰 Tools
🪛 zizmor (1.25.2)

[warning] 1-43: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block

(excessive-permissions)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/vuln-scan.yml around lines 1 - 11, The Security Scans
workflow currently runs with default write-all permissions, but security
scanning only requires read access. Add an explicit permissions block to the
workflow (at the top level, after the concurrency section) that specifies
contents: read to follow least-privilege security practices and prevent
potential credential leakage from future modifications to the workflow.

Source: Linters/SAST tools

jobs:
forbidden-pattern-scan:
name: Forbidden Pattern Scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Run forbidden pattern scan
run: bash scripts/workflow/forbidden-pattern-scan.sh "${{ github.workspace }}"

lazarus-scanner:
name: Lazarus Scanner
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Download lazarus_scanner.py
run: |
curl -fsSL -o lazarus_scanner.py \
https://raw.githubusercontent.com/hngprojects/lazarus-scanner/main/lazarus_scanner.py
[ -s lazarus_scanner.py ] || { echo "FAIL: lazarus_scanner.py is empty or missing"; exit 1; }

- name: Run Lazarus scanner
run: python3 lazarus_scanner.py
Comment on lines +35 to +42

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Remote code execution without integrity verification is a supply-chain risk.

The workflow downloads and executes a Python script from an external repository with no checksum validation. If that repository is compromised, malicious code runs with full repository access. For a security-focused workflow, this is particularly concerning.

Consider pinning to a specific commit and verifying a SHA256 checksum:

🛡️ Proposed fix with checksum verification
             - name: Download lazarus_scanner.py
               run: |
-                  curl -fsSL -o lazarus_scanner.py \
-                    https://raw.githubusercontent.com/hngprojects/lazarus-scanner/main/lazarus_scanner.py
-                  [ -s lazarus_scanner.py ] || { echo "FAIL: lazarus_scanner.py is empty or missing"; exit 1; }
+                  SCANNER_SHA256="<expected-sha256-hash>"  # Pin to known-good hash
+                  curl -fsSL -o lazarus_scanner.py \
+                    https://raw.githubusercontent.com/hngprojects/lazarus-scanner/<commit-sha>/lazarus_scanner.py
+                  echo "${SCANNER_SHA256}  lazarus_scanner.py" | sha256sum -c - || {
+                    echo "FAIL: checksum mismatch for lazarus_scanner.py"; exit 1;
+                  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/vuln-scan.yml around lines 35 - 42, The workflow downloads
lazarus_scanner.py from the main branch of an external repository without any
integrity verification, creating a supply-chain attack risk. Modify the download
step to pin the URL to a specific commit hash instead of main, and add SHA256
checksum verification after the download. Capture the expected checksum for that
specific commit version and add a verification step using sha256sum that
validates the downloaded file before the "Run Lazarus scanner" step executes
python3 lazarus_scanner.py. The checksum verification should fail and exit with
an error message if the hash does not match, preventing execution of unverified
code.

110 changes: 110 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# Contributing to Dequel

Thank you for your interest in contributing! Here's how to get started.

## Getting Started

1. Fork and clone the repo
2. Install dependencies: `bun install`
3. Read [`AGENTS.md`](./AGENTS.md) for the full architecture and conventions

## Reporting Bugs

Open a [Bug Report](https://github.com/Lftobs/dequel/issues/new?template=bug_report.yml). Include:

- Steps to reproduce
- Expected vs actual behavior
- Dequel version (`VERSION` file or `scripts/dequel status`)
- Environment details (OS, Docker version, browser if relevant)

## Suggesting Features

Open a [Feature Request](https://github.com/Lftobs/dequel/issues/new?template=feature_request.yml). Describe:

- The problem you're solving
- Your proposed solution
- Any alternatives considered
- Whether you'd like to implement it yourself

## Development

### Running Locally

```bash
# API (port 3001)
bun apps/api/src/index.ts

# Web dashboard (port 3000)
bun apps/web/src/main.tsx

# Docs (port 4321)
bun apps/docs/src/main.tsx
Comment on lines +34 to +41

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for port configurations in API, web, and docs apps
echo "=== Checking API entry point for port configuration ==="
fd -e 'index.ts|main.ts|config.ts' apps/api/src --max-depth 3 -x grep -l '3001\|17474\|PORT' {} \;

echo -e "\n=== Checking Web entry point ==="
fd -e 'main.tsx' apps/web/src --max-depth 2 -x grep -l '3000\|PORT' {} \;

echo -e "\n=== Checking Docs entry point and port ==="
fd -e 'main.tsx' apps/docs/src --max-depth 2 | head -5
fd -e 'main.tsx|index.ts' apps/docs/src --max-depth 2 -x grep -l '4321\|PORT' {} \;

Repository: Lftobs/dequel

Length of output: 1633


🏁 Script executed:

#!/bin/bash
# List directory structure first
echo "=== Repository structure ==="
ls -la apps/ 2>/dev/null | head -20

echo -e "\n=== API src files ==="
find apps/api/src -type f -name "*.ts" -o -name "*.js" 2>/dev/null | head -10

echo -e "\n=== Web src files ==="
find apps/web/src -type f -name "*.tsx" -o -name "*.ts" 2>/dev/null | head -10

echo -e "\n=== Docs src files ==="
find apps/docs/src -type f -name "*.tsx" -o -name "*.ts" -o -name "*.jsx" -o -name "*.js" 2>/dev/null | head -10

echo -e "\n=== Searching for port 3001 references ==="
rg '3001' apps/ -t ts -t tsx -t js -t json 2>/dev/null | head -20

echo -e "\n=== Searching for port 3000 references ==="
rg '3000' apps/ -t ts -t tsx -t js -t json 2>/dev/null | head -20

echo -e "\n=== Searching for port 4321 references ==="
rg '4321' apps/ -t ts -t tsx -t js -t json 2>/dev/null | head -20

echo -e "\n=== Checking API index.ts content ==="
cat apps/api/src/index.ts 2>/dev/null | head -50

echo -e "\n=== Checking Web main.tsx content ==="
cat apps/web/src/main.tsx 2>/dev/null | head -50

echo -e "\n=== Checking Docs main.tsx content ==="
cat apps/docs/src/main.tsx 2>/dev/null | head -50

Repository: Lftobs/dequel

Length of output: 3954


🏁 Script executed:

#!/bin/bash
# Find config files in docs
echo "=== All files in apps/docs ==="
find apps/docs -type f 2>/dev/null

echo -e "\n=== Check for astro.config or package.json ==="
find apps/docs -name "*.config.*" -o -name "package.json" 2>/dev/null

echo -e "\n=== Full API index.ts ==="
wc -l apps/api/src/index.ts
cat apps/api/src/index.ts

echo -e "\n=== Search for listen/port binding in API ==="
rg 'listen|port|\.listen\|3001' apps/api/ -i 2>/dev/null | head -30

Repository: Lftobs/dequel

Length of output: 6180


🏁 Script executed:

#!/bin/bash
echo "=== API config.ts to find port defaults ==="
cat apps/api/src/utils/config.ts | head -100

echo -e "\n=== Docs astro.config.mjs ==="
cat apps/docs/astro.config.mjs

echo -e "\n=== API package.json scripts ==="
cat apps/api/package.json | grep -A 10 '"scripts"'

echo -e "\n=== Web package.json scripts ==="
cat apps/web/package.json | grep -A 10 '"scripts"'

echo -e "\n=== Docs package.json scripts ==="
cat apps/docs/package.json | grep -A 10 '"scripts"'

echo -e "\n=== CONTRIBUTING.md content around lines 34-41 ==="
cat CONTRIBUTING.md | sed -n '30,45p'

Repository: Lftobs/dequel

Length of output: 3494


Fix incorrect ports and entry point commands in local development guide.

The specified ports and entry point commands are incorrect. API defaults to port 17474 (configured via PORT env var, not 3001), Web dev runs on Vite's default 5173 (preview uses 3000), and Docs is an Astro project running on port 3000—not 4321. More critically, the entry point commands are wrong: bun apps/web/src/main.tsx and bun apps/docs/src/main.tsx files do not exist. Use the package.json scripts instead:

# API (port 17474 by default)
bun run dev

# Web dashboard (port 5173 by default for dev)
bun run dev

# Docs (port 3000 by default)
bun run dev

Or run from the workspace root with workspace filters if configured.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CONTRIBUTING.md` around lines 34 - 41, Update the local development guide
section in CONTRIBUTING.md to correct the port numbers and entry point commands
for all three services. Replace the API section comment and command to use port
17474 (the default) with the command `bun run dev`. Update the Web dashboard
section to specify port 5173 for development (not 3000) with the command `bun
run dev`. Update the Docs section to use port 3000 (not 4321) with the command
`bun run dev`. Remove the incorrect file paths (`bun apps/web/src/main.tsx` and
`bun apps/docs/src/main.tsx`) and replace them with the proper `bun run dev`
command, as the original commands reference non-existent entry point files.
Optionally add a note that these commands can also be run from the workspace
root with appropriate filters if configured.

```

### Code Conventions

- **No comments** in source code unless absolutely necessary
- **Named exports** over default exports
- **Functional components + hooks** in React
- **Tailwind CSS** for styling (web and docs)
- Max ~500 lines per file — split into feature-grouped directories
- `set -euo pipefail` in all bash scripts

### Database Migrations

```bash
# Generate migration from schema changes
bunx drizzle-kit generate

# Push schema directly (dev only)
bunx drizzle-kit push
```

### Testing

```bash
# API tests
bun test
```

Always run `bun test` in `apps/api/` before committing API changes.

### Versioning

```bash
# Bump version across the codebase
./bump.sh v0.2.0
```

This updates `VERSION`, all `package.json` files, and optionally adds a changelog entry.

## Pull Requests

1. Create a PR from your fork using the [PR template](./.github/PULL_REQUEST_TEMPLATE.md)
2. Ensure all tests pass (`bun test`)
3. Keep changes focused — one feature/fix per PR
4. Update documentation if your change affects user-facing behavior
5. If changing API behavior, update the docs site content

### PR Checklist

- [ ] Tests pass (`bun test` in `apps/api/`)
- [ ] No new warnings or lint errors
- [ ] Documentation updated (if applicable)
- [ ] Version synced (`bun run sync-versions`) if `VERSION` changed
- [ ] Follows code conventions (no comments, named exports, etc.)

## Release Process

Maintainers cut releases by tagging:

```bash
git tag vX.Y.Z
git push origin vX.Y.Z
```

CI builds Docker images to `ghcr.io/lftobs/dequel/{api,web}:X.Y.Z` and creates a GitHub Release.

## Questions?

Open a [Discussion](https://github.com/Lftobs/dequel/discussions) for questions and community support.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 Lftobs

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
24 changes: 16 additions & 8 deletions apps/api/src/orchestrator/pipeline.ts
Original file line number Diff line number Diff line change
Expand Up @@ -626,14 +626,22 @@ export class PipelineOrchestrator {
return false;
} finally {
this.abortControllers.delete(deploymentId);
if (workspacePath)
await cleanupWorkspace(
workspacePath,
);
if (uploadedArchivePath)
await rm(uploadedArchivePath, {
force: true,
});
try {
if (workspacePath)
await cleanupWorkspace(
workspacePath,
);
} catch {
// cleanup failures must never mask the deployment result
}
try {
if (uploadedArchivePath)
await rm(uploadedArchivePath, {
force: true,
});
} catch {
// cleanup failures must never mask the deployment result
}
}
}

Expand Down
Loading
Loading