Compare commits

...

15 Commits

Author SHA1 Message Date
jokob-sk
5df39f984a BE: docker version github action work #1320
Some checks failed
Code checks / check-url-paths (push) Has been cancelled
Code checks / lint (push) Has been cancelled
Code checks / docker-tests (push) Has been cancelled
docker / docker_dev (push) Has been cancelled
Deploy MkDocs / deploy (push) Has been cancelled
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 12:00:18 +11:00
jokob-sk
d007ed711a BE: docker version github action work #1320
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 11:58:11 +11:00
jokob-sk
61824abb9f BE: restore previous version retrieval as a test #1320
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 11:21:24 +11:00
jokob-sk
33c5548fe1 Merge branch 'main' of https://github.com/jokob-sk/NetAlertX 2025-11-30 11:15:25 +11:00
jokob-sk
fd41c395ae DOCS: old link removal
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 11:15:19 +11:00
jokob-sk
1a980844f0 BE: restore previous verison retrieval as a test #1320
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 11:14:45 +11:00
jokob-sk
82e018e284 FE: more defensive network topology hierarchy check #1308
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 10:55:08 +11:00
jokob-sk
e0e1233b1c DOCS: migration docs
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 10:27:33 +11:00
jokob-sk
74677f940e FE: more defensive network topology hierarchy check #1308
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 10:27:23 +11:00
Jokob @NetAlertX
21a4d20579 Merge pull request #1317 from mmomjian/main
Fix typo in warning message for read-only mode
2025-11-29 23:17:43 +00:00
jokob-sk
9634e4e0f7 FE: YYYY-DD-MM timestamp handling #1312
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 09:36:56 +11:00
jokob-sk
00a47ab5d3 FE: config backups saved in incorrect location #1311
Some checks failed
Code checks / check-url-paths (push) Has been cancelled
Code checks / lint (push) Has been cancelled
Code checks / docker-tests (push) Has been cancelled
docker / docker_dev (push) Has been cancelled
Deploy MkDocs / deploy (push) Has been cancelled
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-30 07:42:11 +11:00
Matthew Momjian
59b417705e Fix typo in warning message for read-only mode 2025-11-29 11:02:42 -05:00
jokob-sk
525d082f3d DOCS: volume
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-29 16:53:15 +11:00
jokob-sk
ba3481759b DOCS: Migration callouts
Some checks failed
Code checks / check-url-paths (push) Has been cancelled
Code checks / lint (push) Has been cancelled
Code checks / docker-tests (push) Has been cancelled
docker / docker_dev (push) Has been cancelled
Deploy MkDocs / deploy (push) Has been cancelled
Signed-off-by: jokob-sk <jokob.sk@gmail.com>
2025-11-29 16:50:06 +11:00
16 changed files with 372 additions and 330 deletions

View File

@@ -47,6 +47,12 @@ jobs:
id: get_version
run: echo "version=Dev" >> $GITHUB_OUTPUT
# --- debug output
- name: Debug version
run: |
echo "GITHUB_REF: $GITHUB_REF"
echo "Version: '${{ steps.get_version.outputs.version }}'"
# --- Write the timestamped version to .VERSION file
- name: Create .VERSION file
run: echo "${{ steps.timestamp.outputs.version }}" > .VERSION

View File

@@ -32,14 +32,34 @@ jobs:
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
# --- Previous approach Get release version from tag
- name: Set up dynamic build ARGs
id: getargs
run: echo "version=$(cat ./stable/VERSION)" >> $GITHUB_OUTPUT
- name: Get release version
id: get_version_prev
run: echo "::set-output name=version::${GITHUB_REF#refs/tags/}"
- name: Create .VERSION file
run: echo "${{ steps.get_version.outputs.version }}" >> .VERSION_PREV
# --- Get release version from tag
- name: Get release version
id: get_version
run: echo "version=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT
# --- debug output
- name: Debug version
run: |
echo "GITHUB_REF: $GITHUB_REF"
echo "Version: '${{ steps.get_version.outputs.version }}'"
echo "Version prev: '${{ steps.get_version_prev.outputs.version }}'"
# --- Write version to .VERSION file
- name: Create .VERSION file
run: echo "${{ steps.get_version.outputs.version }}" > .VERSION
run: echo -n "${{ steps.get_version.outputs.version }}" > .VERSION
# --- Generate Docker metadata and tags
- name: Docker meta

1
.gitignore vendored
View File

@@ -11,6 +11,7 @@ nohup.out
config/*
.ash_history
.VERSION
.VERSION_PREV
config/pialert.conf
config/app.conf
db/*

View File

@@ -138,6 +138,7 @@ RUN install -d -o ${NETALERTX_USER} -g ${NETALERTX_GROUP} -m 700 ${READ_WRITE_FO
# Copy version information into the image
COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} .[V]ERSION ${NETALERTX_APP}/.VERSION
COPY --chown=${NETALERTX_USER}:${NETALERTX_GROUP} .[V]ERSION ${NETALERTX_APP}/.VERSION_PREV
# Copy the virtualenv from the builder stage
COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV}
@@ -147,12 +148,12 @@ COPY --from=builder --chown=20212:20212 ${VIRTUAL_ENV} ${VIRTUAL_ENV}
# This is done after the copy of the venv to ensure the venv is in place
# although it may be quicker to do it before the copy, it keeps the image
# layers smaller to do it after.
RUN if [ -f '.VERSION' ]; then \
cp '.VERSION' "${NETALERTX_APP}/.VERSION"; \
else \
echo "DEVELOPMENT 00000000" > "${NETALERTX_APP}/.VERSION"; \
fi && \
chown 20212:20212 "${NETALERTX_APP}/.VERSION" && \
RUN for vfile in .VERSION .VERSION_PREV; do \
if [ ! -f "${NETALERTX_APP}/${vfile}" ]; then \
echo "DEVELOPMENT 00000000" > "${NETALERTX_APP}/${vfile}"; \
fi; \
chown 20212:20212 "${NETALERTX_APP}/${vfile}"; \
done && \
apk add --no-cache libcap && \
setcap cap_net_raw+ep /bin/busybox && \
setcap cap_net_raw,cap_net_admin+eip /usr/bin/nmap && \

View File

@@ -34,9 +34,7 @@ Get visibility of what's going on on your WIFI/LAN network and enable presence d
## 🚀 Quick Start
> [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
> ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
Start NetAlertX in seconds with Docker:

View File

@@ -1,9 +1,7 @@
# NetAlertX and Docker Compose
> [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
> ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
Great care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.Good care is taken to ensure NetAlertX meets the needs of everyone while being flexible enough for anyone. This document outlines how you can configure your docker-compose. There are many settings, so we recommend using the Baseline Docker Compose as-is, or modifying it for your system.

View File

@@ -61,8 +61,7 @@ See alternative [docked-compose examples](https://github.com/jokob-sk/NetAlertX/
| Required | Path | Description |
| :------------- | :------------- | :-------------|
| ✅ | `:/data/config` | Folder which will contain the `app.conf` & `devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files |
| ✅ | `:/data/db` | Folder which will contain the `app.db` database file |
| ✅ | `:/data` | Folder which will contain the `/db/app.db`, `/config/app.conf` & `/config/devices.csv` ([read about devices.csv](https://github.com/jokob-sk/NetAlertX/blob/main/docs/DEVICES_BULK_EDITING.md)) files |
| ✅ | `/etc/localtime:/etc/localtime:ro` | Ensuring the timezone is teh same as on teh server. |
| | `:/tmp/log` | Logs folder useful for debugging if you have issues setting up the container |
| | `:/tmp/api` | The [API endpoint](https://github.com/jokob-sk/NetAlertX/blob/main/docs/API.md) containing static (but regularly updated) json and other files. Path configurable via `NETALERTX_API` environment variable. |

View File

@@ -1,9 +1,7 @@
# The NetAlertX Container Operator's Guide
> [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
> ⚠️ **Important:** The docker-compose has recently changed. Carefully read the [Migration guide](https://jokob-sk.github.io/NetAlertX/MIGRATION/?h=migrat#12-migration-from-netalertx-v25524) for detailed instructions.
This guide assumes you are starting with the official `docker-compose.yml` file provided with the project. We strongly recommend you start with or migrate to this file as your baseline and modify it to suit your specific needs (e.g., changing file paths). While there are many ways to configure NetAlertX, the default file is designed to meet the mandatory security baseline with layer-2 networking capabilities while operating securely and without startup warnings.

View File

@@ -62,7 +62,7 @@ docker run -it --rm --name netalertx --user "0" \
>
> `sudo chown -R 20211:20211 /local_data_dir`
>
> `sudo chmod -R a+rwx /local_data_dir1`
> `sudo chmod -R a+rwx /local_data_dir`
>
---

View File

@@ -1,11 +1,5 @@
# Migration
> [!WARNING]
> ⚠️ **Important:** The documentation has been recently updated and some instructions may have changed.
> If you are using the currently live production image, please follow the instructions on [Docker Hub](https://hub.docker.com/r/jokobsk/netalertx) for building and running the container.
> These docs reflect the latest development version and may differ from the production image.
When upgrading from older versions of NetAlertX (or PiAlert by jokob-sk), follow the migration steps below to ensure your data and configuration are properly transferred.
> [!TIP]
@@ -259,12 +253,11 @@ docker run -it --rm --name netalertx --user "0" \
ghcr.io/jokob-sk/netalertx:latest
```
..or alternatively execute:
...or alternatively execute:
```bash
sudo chown -R 20211:20211 /local_data_dir/config
sudo chown -R 20211:20211 /local_data_dir/db
sudo chmod -R a+rwx /local_data_dir/
sudo chown -R 20211:20211 /local_data_dir
sudo chmod -R a+rwx /local_data_dir
```
7. Stop the container

View File

@@ -63,7 +63,6 @@ There is also an in-app Help / FAQ section that should be answering frequently a
#### ♻ Misc
- [Version history (legacy)](./VERSIONS_HISTORY.md)
- [Reverse proxy (Nginx, Apache, SWAG)](./REVERSE_PROXY.md)
- [Installing Updates](./UPDATES.md)
- [Setting up Authelia](./AUTHELIA.md) (DRAFT)

View File

@@ -84,5 +84,5 @@ services:
>
> `sudo chown -R 20211:20211 /local_data_dir`
>
> `sudo chmod -R a+rwx /local_data_dir1`
> `sudo chmod -R a+rwx /local_data_dir`
>

View File

@@ -378,7 +378,7 @@ function localizeTimestamp(input) {
let tz = getSetting("TIMEZONE") || 'Europe/Berlin';
input = String(input || '').trim();
// 1. Unix timestamps (10 or 13 digits)
// 1. Unix timestamps (10 or 13 digits)
if (/^\d+$/.test(input)) {
const ms = input.length === 10 ? parseInt(input, 10) * 1000 : parseInt(input, 10);
return new Intl.DateTimeFormat('default', {
@@ -389,39 +389,53 @@ function localizeTimestamp(input) {
}).format(new Date(ms));
}
// 2. European DD/MM/YYYY
// 2. European DD/MM/YYYY
let match = input.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})(?:[ ,]+(\d{1,2}:\d{2}(?::\d{2})?))?(.*)$/);
if (match) {
let [ , d, m, y, t = "00:00:00", tzPart = "" ] = match;
let [, d, m, y, t = "00:00:00", tzPart = ""] = match;
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${t.length===5?t+":00":t}${tzPart}`;
return formatSafe(iso, tz);
}
// 3. US MM/DD/YYYY
// 3. US MM/DD/YYYY
match = input.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})(?:[ ,]+(\d{1,2}:\d{2}(?::\d{2})?))?(.*)$/);
if (match) {
let [ , m, d, y, t = "00:00:00", tzPart = "" ] = match;
let [, m, d, y, t = "00:00:00", tzPart = ""] = match;
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${t.length===5?t+":00":t}${tzPart}`;
return formatSafe(iso, tz);
}
// 4. ISO-style (with T, Z, offsets)
match = input.match(/^(\d{4}-\d{1,2}-\d{1,2})[ T](\d{1,2}:\d{2}(?::\d{2})?)(Z|[+-]\d{2}:?\d{2})?$/);
// 4. ISO YYYY-MM-DD with optional Z/+offset
match = input.match(/^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])[ T](\d{1,2}:\d{2}(?::\d{2})?)(Z|[+-]\d{2}:?\d{2})?$/);
if (match) {
let [ , ymd, time, offset = "" ] = match;
// normalize to YYYY-MM-DD
let [y, m, d] = ymd.split('-').map(x => x.padStart(2,'0'));
let [, y, m, d, time, offset = ""] = match;
const iso = `${y}-${m}-${d}T${time.length===5?time+":00":time}${offset}`;
return formatSafe(iso, tz);
}
// 5. RFC2822 / "25 Aug 2025 13:45:22 +0200"
// 5. RFC2822 / "25 Aug 2025 13:45:22 +0200"
match = input.match(/^\d{1,2} [A-Za-z]{3,} \d{4}/);
if (match) {
return formatSafe(input, tz);
}
// 6. Fallback (whatever Date() can parse)
// 6. DD-MM-YYYY with optional time
match = input.match(/^(\d{1,2})-(\d{1,2})-(\d{4})(?:[ T](\d{1,2}:\d{2}(?::\d{2})?))?$/);
if (match) {
let [, d, m, y, time = "00:00:00"] = match;
const iso = `${y}-${m.padStart(2,'0')}-${d.padStart(2,'0')}T${time.length===5?time+":00":time}`;
return formatSafe(iso, tz);
}
// 7. Strict YYYY-DD-MM with optional time
match = input.match(/^(\d{4})-(0[1-9]|[12]\d|3[01])-(0[1-9]|1[0-2])(?:[ T](\d{1,2}:\d{2}(?::\d{2})?))?$/);
if (match) {
let [, y, d, m, time = "00:00:00"] = match;
const iso = `${y}-${m}-${d}T${time.length === 5 ? time + ":00" : time}`;
return formatSafe(iso, tz);
}
// 8. Fallback
return formatSafe(input, tz);
function formatSafe(str, tz) {
@@ -440,6 +454,7 @@ function localizeTimestamp(input) {
}
// ----------------------------------------------------
/**
* Replaces double quotes within single-quoted strings, then converts all single quotes to double quotes,
@@ -1629,7 +1644,7 @@ async function executeOnce() {
await cacheSettings();
await cacheStrings();
console.log("All AJAX callbacks have completed");
console.log("All AJAX callbacks have completed");
onAllCallsComplete();
} catch (error) {
console.error("Error:", error);

View File

@@ -521,12 +521,16 @@ function getChildren(node, list, path, visited = [])
// Loop through all items to find children of the current node
for (var i in list) {
if (list[i].devParentMAC.toLowerCase() == node.devMac.toLowerCase() && !hiddenMacs.includes(list[i].devParentMAC)) {
const item = list[i];
const parentMac = item.devParentMAC || ""; // null-safe
const nodeMac = node.devMac || ""; // null-safe
if (parentMac != "" && parentMac.toLowerCase() == nodeMac.toLowerCase() && !hiddenMacs.includes(parentMac)) {
visibleNodesCount++;
// Process children recursively, passing a copy of the visited list
children.push(getChildren(list[i], list, path + ((path == "") ? "" : '|') + list[i].devParentMAC, visited));
children.push(getChildren(list[i], list, path + ((path == "") ? "" : '|') + parentMac, visited));
}
}
@@ -565,14 +569,27 @@ function getChildren(node, list, path, visited = [])
// ---------------------------------------------------------------------------
function getHierarchy()
{
let internetNode = null;
for(i in deviceListGlobal)
{
if(deviceListGlobal[i].devMac == 'Internet')
{
return (getChildren(deviceListGlobal[i], deviceListGlobal, ''))
internetNode = deviceListGlobal[i];
return (getChildren(internetNode, deviceListGlobal, ''))
break;
}
}
if (!internetNode) {
showModalOk(
getString('Network_Configuration_Error'),
getString('Network_Root_Not_Configured')
);
console.error("getHierarchy(): Internet node not found");
return null;
}
}
//---------------------------------------------------------------------------
@@ -671,8 +688,6 @@ function handleNodeClick(el)
// ---------------------------------------------------------------------------
var myTree;
var emSize;
var nodeHeight;
// var sizeCoefficient = 1.4
@@ -689,10 +704,12 @@ function emToPx(em, element) {
function initTree(myHierarchy)
{
// calculate the drawing area based on teh tree width and available screen size
if(myHierarchy && myHierarchy.type !== "")
{
// calculate the drawing area based on the tree width and available screen size
let baseFontSize = parseFloat($('html').css('font-size'));
let treeAreaHeight = ($(window).height() - 155); ;
// calculate the font size of the leaf nodes to fit everything into the tree area
leafNodesCount == 0 ? 1 : leafNodesCount;
@@ -703,13 +720,6 @@ function initTree(myHierarchy)
// init the drawing area size
$("#networkTree").attr('style', `height:${treeAreaHeight}px; width:${emToPx(screenWidthEm)}px`)
if(myHierarchy.type == "")
{
showModalOk(getString('Network_Configuration_Error'), getString('Network_Root_Not_Configured'))
return;
}
// handle canvas and node size if only a few nodes
emSize > 1 ? emSize = 1 : emSize = emSize;
@@ -823,6 +833,10 @@ function initTree(myHierarchy)
// hide spinning icon
hideSpinner()
} else
{
console.error("getHierarchy() not returning expected result");
}
}

View File

@@ -303,7 +303,7 @@ function saveSettings()
// save to the file
$new_name = $config_file.'_'.$timestamp.'.backup';
$new_location = $configFolderPath.$new_name;
$new_location = $configFolderPath.'/'.$new_name;
if(file_exists( $fullConfPath) != 1)
{

View File

@@ -14,7 +14,7 @@ if ! awk '$2 == "/" && $4 ~ /ro/ {found=1} END {exit !found}' /proc/mounts; then
══════════════════════════════════════════════════════════════════════════════
⚠️ Warning: Container is running as read-write, not in read-only mode.
Please mount the root filesystem as --read-only or use read-only: true
Please mount the root filesystem as --read-only or use read_only: true
https://github.com/jokob-sk/NetAlertX/blob/main/docs/docker-troubleshooting/read-only-filesystem.md
══════════════════════════════════════════════════════════════════════════════
EOF