Skip to content

Commit 9e20c1d

Browse files
chore: more validation, use frozen lockfile in ci, remove on delete cascade
Signed-off-by: Henry <mail@henrygressmann.de>
1 parent aaebacc commit 9e20c1d

14 files changed

Lines changed: 97 additions & 29 deletions

File tree

.github/workflows/container.yaml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ jobs:
2121

2222
runs-on: ubuntu-24.04
2323
steps:
24-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
24+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
2525
with:
2626
persist-credentials: false
2727
- name: Setup Docker Buildx
28-
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
28+
uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4.1.0
2929
- name: Extract Semver
3030
id: semver
3131
env:
@@ -34,7 +34,7 @@ jobs:
3434
SEMVER_VERSION=$(echo "$INPUT_TAG" | sed -E 's/liwan-v//')
3535
echo "SEMVER_VERSION=${SEMVER_VERSION}" >> "$GITHUB_OUTPUT"
3636
- name: Setup Docker Metadata
37-
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
37+
uses: docker/metadata-action@80c7e94dd9b9319bd5eb7a0e0fe9291e23a2a2e9 # v6.1.0
3838
id: meta
3939
with:
4040
images: ghcr.io/${{ github.actor }}/liwan
@@ -44,7 +44,7 @@ jobs:
4444
type=semver,pattern={{major}},value=${{ steps.semver.outputs.SEMVER_VERSION }}
4545
type=raw,edge
4646
- name: Login to GitHub Container Registry
47-
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
47+
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
4848
with:
4949
registry: ghcr.io
5050
username: ${{ github.actor }}
@@ -66,7 +66,7 @@ jobs:
6666
6767
wait
6868
- name: Build and push Docker images
69-
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
69+
uses: docker/build-push-action@f9f3042f7e2789586610d6e8b85c8f03e5195baf # v7.2.0
7070
with:
7171
context: .
7272
file: ./scripts/Containerfile

.github/workflows/release.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
contents: write
1212
runs-on: ubuntu-24.04
1313
steps:
14-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
14+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
1515
with:
1616
persist-credentials: false
1717
- uses: taiki-e/create-gh-release-action@eba8ea96c86cca8a37f1b56e94b4d13301fba651 # v1.11.0
@@ -27,7 +27,7 @@ jobs:
2727
permissions:
2828
contents: write
2929
steps:
30-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
30+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
3131
with:
3232
persist-credentials: false
3333
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
@@ -36,7 +36,7 @@ jobs:
3636
no-cache: true
3737
- name: Build web project
3838
run: |
39-
bun install
39+
bun install --frozen-lockfile
4040
bun run build
4141
working-directory: ./web
4242
- name: Upload web assets
@@ -64,7 +64,7 @@ jobs:
6464

6565
runs-on: ${{ matrix.os }}
6666
steps:
67-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
67+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
6868
with:
6969
persist-credentials: false
7070
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1

.github/workflows/test-web.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
permissions:
2020
contents: read
2121
steps:
22-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
22+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
2323
with:
2424
persist-credentials: false
2525
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0

.github/workflows/test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ jobs:
2323
name: Run tests on ${{ matrix.os }}
2424
runs-on: ${{ matrix.os }}
2525
steps:
26-
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
26+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
2727
with:
2828
persist-credentials: false
2929
- uses: actions-rust-lang/setup-rust-toolchain@46268bd060767258de96ed93c1251119784f2ab6 # v1.16.1

src/app/core/entities.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ impl LiwanEntities {
7171
pub fn delete(&self, id: &str) -> Result<()> {
7272
let mut conn = self.pool.get()?;
7373
let tx = conn.transaction()?;
74+
tx.execute("delete from entity_settings where entity_id = ?", rusqlite::params![id])?;
7475
tx.execute("delete from entities where id = ?", rusqlite::params![id])?;
7576
tx.execute("delete from project_entities where entity_id = ?", rusqlite::params![id])?;
7677
tx.commit()?;

src/app/core/projects.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ impl LiwanProjects {
126126
pub fn delete(&self, id: &str) -> Result<()> {
127127
let mut conn = self.pool.get()?;
128128
let tx = conn.transaction()?;
129+
tx.execute("delete from project_settings where project_id = ?", rusqlite::params![id])?;
129130
tx.execute("delete from projects where id = ?", rusqlite::params![id])?;
130131
tx.execute("delete from project_entities where project_id = ?", rusqlite::params![id])?;
131132
tx.commit()?;

src/app/core/settings.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ impl LiwanSettings {
131131
Ok(())
132132
}
133133

134-
fn reload(&self) -> Result<()> {
134+
/// Reload collection settings from SQLite into the in-memory cache
135+
pub fn reload(&self) -> Result<()> {
135136
let cache = SettingsCache::load(&self.pool)?;
136137
*self.cache.write().expect("collection settings cache poisoned") = cache;
137138
Ok(())

src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
pub const PASSWORD_MIN_LENGTH: usize = 8;
2+
13
pub mod app;
24
pub mod cli;
35
pub mod config;

src/migrations/app/V2__settings.sql

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ create table entity_settings (
2727
history_mode text not null default 'inherit',
2828
history_days integer,
2929
ingest_drop_rules_json text not null default '[]',
30-
foreign key (entity_id) references entities(id) on delete cascade
30+
foreign key (entity_id) references entities(id)
3131
);
3232

3333
create table project_settings (
3434
project_id text primary key not null,
3535
metric_display_overrides_json text not null default '{}',
3636
dimension_display_overrides_json text not null default '{}',
37-
foreign key (project_id) references projects(id) on delete cascade
37+
foreign key (project_id) references projects(id)
3838
);

src/web/routes/admin.rs

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ use schemars::JsonSchema;
1111
use serde::{Deserialize, Serialize};
1212

1313
use crate::{
14-
app::models::{
15-
CollectionSettings, Entity, EntityCollectionSettings, Project, ProjectDisplaySettings,
16-
ResolvedCollectionSettings, UserRole,
14+
PASSWORD_MIN_LENGTH,
15+
app::{
16+
models::{
17+
CollectionSettings, Entity, EntityCollectionSettings, Project, ProjectDisplaySettings,
18+
ResolvedCollectionSettings, UserRole,
19+
},
20+
reports::{Dimension, Metric},
1721
},
18-
app::reports::{Dimension, Metric},
1922
utils::validate::can_access_project,
2023
web::{
2124
RouterState,
@@ -267,14 +270,18 @@ async fn update_user_password(
267270
app: State<RouterState>,
268271
Path(username): Path<String>,
269272
Auth(session_user): Auth,
270-
password: Json<UpdatePasswordRequest>,
273+
params: Json<UpdatePasswordRequest>,
271274
) -> ApiResult<impl IntoApiResponse> {
272275
if session_user.role != UserRole::Admin || username != session_user.username {
273276
http_bail!(StatusCode::FORBIDDEN, "Forbidden")
274277
}
275278

279+
if params.password.len() < PASSWORD_MIN_LENGTH {
280+
http_bail!(StatusCode::BAD_REQUEST, "password must be at least 8 characters long");
281+
}
282+
276283
app.users
277-
.update_password(&username, &password.password)
284+
.update_password(&username, &params.password)
278285
.http_err("Failed to update password", StatusCode::INTERNAL_SERVER_ERROR)?;
279286

280287
Ok(empty_response())
@@ -301,14 +308,18 @@ async fn remove_user(
301308
async fn create_user(
302309
app: State<RouterState>,
303310
Auth(session_user): Auth,
304-
user: Json<CreateUserRequest>,
311+
params: Json<CreateUserRequest>,
305312
) -> ApiResult<impl IntoApiResponse> {
306313
if session_user.role != UserRole::Admin {
307314
http_bail!(StatusCode::FORBIDDEN, "Forbidden")
308315
}
309316

317+
if params.password.len() < PASSWORD_MIN_LENGTH {
318+
http_bail!(StatusCode::BAD_REQUEST, "password must be at least 8 characters long");
319+
}
320+
310321
let app = app.app.clone();
311-
tokio::task::spawn_blocking(move || app.users.create(&user.username, &user.password, user.role, &[]))
322+
tokio::task::spawn_blocking(move || app.users.create(&params.username, &params.password, params.role, &[]))
312323
.await
313324
.http_err("Failed to create user", StatusCode::INTERNAL_SERVER_ERROR)?
314325
.http_err("Failed to create user", StatusCode::INTERNAL_SERVER_ERROR)?;
@@ -646,6 +657,7 @@ async fn entity_delete_handler(
646657
}
647658

648659
app.entities.delete(&entity_id).http_err("Failed to delete entity", StatusCode::INTERNAL_SERVER_ERROR)?;
660+
app.settings.reload().http_err("Failed to reload collection settings", StatusCode::INTERNAL_SERVER_ERROR)?;
649661

650662
Ok(empty_response())
651663
}

0 commit comments

Comments
 (0)