Skip to content
Merged
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
98 changes: 46 additions & 52 deletions .github/workflows/snyk-security.yml
Original file line number Diff line number Diff line change
@@ -1,79 +1,73 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# A sample workflow which sets up Snyk to analyze the full Snyk platform (Snyk Open Source, Snyk Code,
# Snyk Container and Snyk Infrastructure as Code)
# The setup installs the Snyk CLI - for more details on the possible commands
# check https://docs.snyk.io/snyk-cli/cli-reference
# The results of Snyk Code are then uploaded to GitHub Security Code Scanning
#
# In order to use the Snyk Action you will need to have a Snyk API token.
# More details in https://github.com/snyk/actions#getting-your-snyk-token
# or you can signup for free at https://snyk.io/login
#
# For more examples, including how to limit scans to only high-severity issues
# and fail PR checks, see https://github.com/snyk/actions/

name: Snyk Security

on:
push:
branches: ["**"] # Matches every branch in the repository
branches: ["**"]
pull_request:
branches: ["**"]
workflow_dispatch: # Still keeps the "manual" run button
workflow_dispatch:

permissions:
contents: read

jobs:
snyk:
permissions:
contents: read # for actions/checkout to fetch code
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status
contents: read
security-events: write
actions: read
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Snyk CLI to check for security issues
# Snyk can be used to break the build when it detects security issues.
# In this case we want to upload the SAST issues to GitHub Code Scanning
uses: snyk/actions/setup@806182742461562b67788a64410098c9d9b96adb
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'

- name: Install dependencies
run: npm install

# For Snyk Open Source you must first set up the development environment for your application's dependencies
# For example for Node
#- uses: actions/setup-node@v4
# with:
# node-version: 20
- name: Set up Snyk CLI
uses: snyk/actions/setup@master

# --- DEBUG STEP 1: Verify token presence and length ---
- name: Verify Secret Presence
run: |
if [ -z "$SNYK_TOKEN" ]; then
echo "❌ ERROR: SNYK_TOKEN is empty in the runner!"
exit 1
else
echo "✅ SNYK_TOKEN detected. Length: ${#SNYK_TOKEN} characters."
echo "If length is not ~36, your copy/paste was incomplete."
fi
env:
# This is where you will need to introduce the Snyk API token created with your Snyk account
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# Runs Snyk Code (SAST) analysis and uploads result into GitHub.
# Use || true to not fail the pipeline
- name: Snyk Code test
run: snyk code test --sarif > snyk-code.sarif # || true
# --- DEBUG STEP 2: Validate token resolves to a real identity ---
- name: Validate Snyk Auth (whoami)
run: snyk whoami --experimental
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# Runs Snyk Open Source (SCA) analysis and uploads result to Snyk.
- name: Snyk Open Source monitor
run: snyk monitor --all-projects
- name: Snyk Code test
run: snyk code test --sarif --target-reference="${{ github.ref_name }}" > snyk-code.sarif || true
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# Runs Snyk Infrastructure as Code (IaC) analysis and uploads result to Snyk.
# Use || true to not fail the pipeline.
- name: Snyk IaC test and report
run: snyk iac test --report # || true
# --- DEBUG STEP 3: Verify SARIF output ---
- name: Check SARIF file
run: |
echo "SARIF file size: $(wc -c < snyk-code.sarif) bytes"
head -5 snyk-code.sarif

# Build the docker image for testing
- name: Build a Docker image
run: docker build -t your/image-to-test .
# Runs Snyk Container (Container and SCA) analysis and uploads result to Snyk.
- name: Snyk Container monitor
run: snyk container monitor your/image-to-test --file=Dockerfile
- name: Snyk Open Source monitor
run: snyk monitor --all-projects --target-reference="${{ github.ref_name }}"
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

# Push the Snyk Code results into GitHub Code Scanning tab
- name: Upload result to GitHub Code Scanning
uses: github/codeql-action/upload-sarif@v3
with:
Expand Down
45 changes: 45 additions & 0 deletions .snyk
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Snyk (https://snyk.io) policy file
# https://docs.snyk.io/snyk-cli/test-for-vulnerabilities/the-.snyk-file
version: v1.25.0

ignore:
# CWE-79: DOM-based XSS
# SSLM is a local-only web application that runs on localhost and is never
# exposed to the internet. DOM XSS via server-returned data is not
# exploitable in this context.
javascript/DomBasedXss:
- 'public/js/importWizard.js':
reason: 'Local-only application running on localhost. No internet exposure.'
expires: '2027-02-24T00:00:00.000Z'
created: '2026-02-24T00:00:00.000Z'
- 'public/js/mergeWizard.js':
reason: 'Local-only application running on localhost. No internet exposure.'
expires: '2027-02-24T00:00:00.000Z'
created: '2026-02-24T00:00:00.000Z'
- 'public/js/modeSelection.js':
reason: 'Local-only application running on localhost. No internet exposure.'
expires: '2027-02-24T00:00:00.000Z'
created: '2026-02-24T00:00:00.000Z'
- 'public/js/app.js':
reason: 'Local-only application running on localhost. No internet exposure.'
expires: '2027-02-24T00:00:00.000Z'
created: '2026-02-24T00:00:00.000Z'
- 'public/js/dashboard.js':
reason: 'Local-only application running on localhost. No internet exposure.'
expires: '2027-02-24T00:00:00.000Z'
created: '2026-02-24T00:00:00.000Z'

# CWE-770: Allocation of Resources Without Limits or Throttling
# Rate limiting is implemented via the custom createRateLimiter() middleware.
# Every endpoint uses one of: heavyOpLimiter (10/min), analysisLimiter (30/min),
# or lightLimiter (200/min). Snyk does not recognise custom middleware as a
# rate-limiting mechanism.
# NOTE: This entry applies to Snyk Open Source only. Snyk Code (SAST) ignores
# must be managed via the Snyk web platform — they are not read from this file.
javascript/NoRateLimitingForExpensiveWebOperation:
- 'server.js':
reason: 'Custom createRateLimiter() middleware applied to all endpoints (heavyOpLimiter / analysisLimiter / lightLimiter).'
expires: '2027-02-25T00:00:00.000Z'
created: '2026-02-25T00:00:00.000Z'

patch: {}
32 changes: 30 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ SSLM (SeeStar Library Manager) is an application that manages astrophotography f
| Version | Status | Date | Notes |
|---------|--------|------|-------|
| **v1.0.0-beta.2** | 🟡 **Current — Public Beta** | February 2026 | First public release. Windows installer available on GitHub Releases. |
| **post-beta.2** | 🔧 **In Development** | February 2026 | Mount Mode support + cosmetic improvements (not yet released). |

**GitHub Releases**: https://github.com/AstroNoob-Tools/SSLM/releases

Expand Down Expand Up @@ -84,6 +85,24 @@ All five phases are complete. The application has been packaged and released as
- ✅ Native `fetch` used throughout — no new npm dependencies
- ✅ Graceful degradation: network failure or unrecognised object leaves detail page unaffected

**Mount Mode Support - COMPLETE**: Dual sub-frame folder support (EQ + Alt/Az)
- ✅ SeeStar names sub-frame folders differently per mount mode: `_sub` (EQ) and `-sub` (Alt/Az)
- ✅ `catalogParser.js`: detects both `_sub` and `-sub` suffixes; adds `mountMode: 'eq' | 'altaz' | null` to parsed result
- ✅ `fileAnalyzer.js`: dual sub-folder fields `subFolderEq` + `subFolderAltAz` per object; `mountMode: 'eq' | 'altaz' | 'both'`; backward-compat `subFolder` alias (prefers Eq)
- ✅ `importService.js`, `mergeService.js`, `diskSpaceValidator.js`: `isSubframeNonFit()` now matches both `-sub` and `_sub`
- ✅ `fileCleanup.js`: `cleanupSubFrameDirectories()` and `getSubFrameCleanupInfo()` iterate over both sub-folders per object; `deleteSessionFiles()` accepts `subFiles` as `[{ folder, file }]` to support files from two sub-folder paths
- ✅ `server.js`: `POST /api/cleanup/session` updated — `subFiles` carries per-file folder, `subFolderPath` removed
- ✅ Dashboard: dedicated **Mount** column in objects table with EQ / Alt/Az / Both badges (colour-coded); mount mode badge in object detail header
- ✅ Object detail sub-frames section renders one card per sub-folder, each clearly labelled with mount mode
- ✅ Session file matching (`_getSessionFiles`) searches both sub-folders; returns `{ folder, file }` objects
- ✅ Delete session sends `subFiles` as `[{ folder, file }]` covering both sub-folders
- ✅ Sub-frame cleanup confirmation message is mode-aware (lists correct folder suffixes)

**Cosmetic Improvements - COMPLETE**: Dashboard display refinements
- ✅ Object detail summary cards rendered in compact single-row layout (5 columns, icon + label + value inline)
- ✅ Sub-frames folder detail grid uses `2fr + 4×1fr` so Files / Size / .fit Files / Other Files stay on one row
- ✅ Integration Time in object detail banner and objects table falls back to `sum(stackCount × exposure)` from parsed sessions when no sub-frames exist — consistent with the Imaging Sessions table

**Phase 4 - COMPLETE**: Windows installer & application branding
- ✅ Self-contained `sslm.exe` built with `@yao-pkg/pkg` (Node.js runtime bundled)
- ✅ Windows installer built with Inno Setup 6 (`installer/sslm.iss`)
Expand Down Expand Up @@ -149,12 +168,21 @@ Contains stacked/processed final images:
- `[filter]`: Filter used (e.g., IRCUT, LP - Light Pollution filter)
- `[timestamp]`: Date and time in format YYYYMMDD-HHMMSS

#### Sub-frames Directory (e.g., `NGC 6729_sub/`)
#### Sub-frames Directory
The sub-frame folder suffix depends on the mount mode used during capture:

| Mount Mode | Suffix | Example |
|------------|--------|---------|
| **EQ** (equatorial) | `_sub` | `NGC 6729_sub/` |
| **Alt/Az** (alt-azimuth) | `-sub` | `NGC 6729-sub/` |

An object can have **both** sub-frame folders simultaneously if sessions were captured in different mount modes on different nights.

Contains individual light frames (sub-exposures):
- **Light frames**: `Light_[ObjectName]_[exposure]_[filter]_[timestamp].fit`
- Example: `Light_NGC 6729_30.0s_IRCUT_20250822-203353.fit`
- **Corresponding files**: Each .fit has matching .jpg and _thn.jpg versions
- **Note**: JPG files in `_sub` directories are not needed and can be deleted to save space
- **Note**: JPG files in sub-frame directories are not needed and can be deleted to save space

### Pattern 2: Captures Without Subframes

Expand Down
Loading
Loading