1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
Commit graph

41 commits

Author SHA1 Message Date
catborise
c1d36053d6 feat(logs): every VM operation writes an audit row the VM's Logs tab finds by UUID
Operations on a VM now write their rows the way the admin audit does: one
row per operation, done or failed with a safe reason, with the user, IP and
host. Each row names the VM ("VM web-1: delete snapshot snap1") and carries
its UUID in the new Logs.instance_uuid column.

- audit_vm and failed_vm wrap audit() and failed() for a VM. A failure the
  view turns into a message is caught outside the block, so its failed row
  is written; busy claims, permission and quota refusals and invalid input
  write nothing. No password, key or XML goes into a row.
- All VM page operations move from addlogmsg to audit_vm, and addlogmsg
  goes. QoS changes and defining a VM from XML are logged now; a gstfsd
  error reply (root password, SSH key) is a failed row, not a done one.
- Partial results are rows of their own: the VM delete, then each disk
  delete; the disk detach, then the volume delete; the migration, then a
  failed autostart restore, NVRAM removal or record on the target.
- Migration rows use the compute name as the host column, as every other
  row does.
- VM job rows (create, clone, snapshots) and their resolutions carry the
  VM's UUID; snapshot job intents now record it. The owner rows of the VM
  page and the accounts pages, and the ownership system rows, carry it too.
- The Logs tab loads vm_logs/<pk>/ and shows the rows with the VM's UUID,
  so a rename keeps the history, two VMs with one name are told apart and
  a VM on two computes is one VM. It gains a Result column. Rows from
  before this change have no UUID and stay on the Logs page only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:14:53 +03:00
catborise
3210ef2eee fix(accounts): a username longer than the field is refused by the login form
Django's login form gives the username its max_length after the field
is built, so a longer username was not refused and reached
authentication. django-axes then stored it in its 255-character column,
which PostgreSQL refuses: a login with a 300-character username was a
500 (SQLite does not enforce the length). Both login forms, with and
without OTP, now check the length, so such a username is a form error
and never reaches authentication, the lockout or the Logs page.

This also turns the PostgreSQL leg of CI green again: the S-16 test
from #167 hit exactly this.
2026-10-23 16:06:10 +03:00
catborise
291690bb20 fix(logs): a typed username cannot forge a record in the file log
Failed logins are logged now, so S-16 applies: what a user types as a
username must not break a row or forge another record. The Logs page
shows each value in its own cell, escaped, and the writer cuts the
username to the 150-character field (Django's login form does not stop
a longer one). The file-log line written when a row cannot be saved
escaped only "\n"; it now escapes "\r" too, so a CR LF in a username
stays one line.
2026-10-23 15:31:00 +03:00
catborise
8c0fbff8f7 feat(logs): admin changes and logins are recorded on the Logs page
The Logs page shows who added, changed or deleted a compute, from web
or API, and every login, failed login, lockout and logout, with the
client address and a Result column (Done, Failed, Unknown for older
rows). A failed change is recorded with its reason and the error still
reaches the user; a refused one is recorded too.

- logs.audit.write saves each row in its own savepoint and never
  raises, so a log write cannot break or undo the action it records.
  The audit() context manager writes one row when the change ends.
- Logs gains success and ip; user, host and instance are wider and
  date is indexed. The page orders by date then id.
- A compute edit names the changed fields; an edit that changes
  nothing writes no row, and an empty password field is no change.
- A compute's VMs leaving the panel get a system row each: owners
  kept on the Removed VMs page, moved to another compute, restored,
  left without owners, or the removed record expired.
- Job rows carry the result. A job's log entry that cannot be
  computed is logged and skipped instead of rolling back the finish
  (test_service.py changes this on purpose).
- Logins are recorded by signal receivers; CustomLoginView is removed
  and the plain LoginView is used. A wrong OTP code is a failed login,
  counted by django-axes toward the lockout.

Panel records and host-side objects follow in the next layers.
2026-10-23 10:30:48 +03:00
catborise
c55f52f025 test: each app keeps its tests in a tests package
131 test modules sat next to the code they test; instances alone had
51 of them beside views.py and utils.py. They move into a
tests/ package per app, and the JavaScript checks into
webvirtcloud/tests/js. Each non-empty tests.py becomes tests/test_views.py;
the empty generated stubs are removed.

Imports of the app's own modules become absolute, paths built from
__file__ go one level up, the live helper is instances.tests.livetest,
and coverage omits */tests/*. The suite discovers the same 960 tests as
before.
2026-10-12 15:17:30 +03:00
catborise
c2fea2aa39 feat(accounts): failed logins lock a user for the address they come from
Nothing limited failed logins: a password could be guessed at the speed
the server answers. django-axes (8.3.1, Django 5.2, Python 3.10-3.13)
now counts them.

- A user is locked for the address the failed logins come from
  (username and IP together), so an attacker cannot lock someone out
  from elsewhere and users behind one NAT address do not share a lock.
  A successful login resets the count. axes sits in front of every
  authentication: the login page with or without OTP, LDAP and the API.
- The number of failed logins (default 5) and the lock time in minutes
  (default 15) are on the Settings page (LOGIN_FAILURE_LIMIT,
  LOGIN_LOCKOUT_MINUTES, added by migration appsettings.0014) and apply
  at once; an invalid value falls back to the default. Unlock with
  "manage.py axes_reset_username <username>".
- Behind the bundled nginx every request comes from 127.0.0.1; the
  client address is read from X-Real-IP, which nginx sets, but only for
  requests from a loopback address or from LOGIN_TRUSTED_PROXIES, so a
  forged header does not escape a lock.

settings.py.template gets the app, middleware, backend and AXES_*
settings; README tells existing installations what to copy. Tests that
call client.login now pass a request, which the axes backend needs.
The new tests fail with axes disabled.
2026-10-06 11:05:03 +03:00
catborise
b04f656d2b ci: replace super-linter with ruff
Super-linter ran from the unpinned :latest image and, because of
branches-ignore: [master], never on pull requests to master. Ruff now
checks syntax errors and pyflakes rules (E9, F) on every push and PR.

Fixes the existing findings: unused imports and variables, an unused
duplicate import in instances/tests.py, and the star import in
accounts/views.py. settings-dev.py keeps its star import of the base
settings.
2026-10-04 01:08:11 +03:00
catborise
fd5aa069be fix: track migrations; installs apply them instead of generating them
The *migrations/* ignore rule is removed. appsettings, computes and
logs pin default_auto_field to AutoField, so makemigrations --check
reports no pending BigAutoField migrations and existing installs need
no schema change.

The Vagrant provisioning no longer runs makemigrations, which created
install-specific migration files that conflict with the committed
history; it only runs migrate.
2026-10-04 01:08:11 +03:00
catborise
4546653b5a fix: serve JSON endpoints as application/json and build DOM safely
Several views returned json.dumps() output through HttpResponse, i.e. as
text/html, and guess_mac_address reflects the URL's vname into it
(reflected XSS). Templates filled the log table and volume dropdowns by
concatenating server data into HTML strings, and log messages contain
user-entered snapshot/disk/clone names (stored XSS that runs when a
superuser opens the Logs tab).

- Use JsonResponse in guess_mac_address, random_mac_address,
  guess_clone_name, sshkeys, storages.get_volumes,
  datasource.os_metadata_json and logs.vm_logs; sshkeys?plain=true is
  served as text/plain.
- stats_tab.html builds log rows with .text(); instance.html and
  create_instance_w2.html build <option> elements with .val().text().
2026-10-02 18:29:11 +03:00
catborise
60565b05b3 fix(tests): decouple tests from local libvirt, support configurable test host, and fix URL/logging bugs 2026-09-25 11:51:45 +03:00
catborise
c31ed28042 test: expand unit test coverage across admin, accounts, vrtManager, logs, appsettings, and datasource 2026-09-25 11:26:53 +03:00
Emre Serdengeçti
1cbdf76df6
logger updates (#31)
* Log for failed login attempts

* Logger configuration for logging to file

* interface fixes

* login log fix, added logged in too

* bootstrap icons setup

* font-awesome icons replaced with bootstrap icons

* replaced i-tags with django_bootstrap_icons

* removed icons library from project

* bug fix

---------

Co-authored-by: catborise <catborise@gmail.com>
2023-08-09 09:20:18 +03:00
catborise
610efd5520 add host name for logs beside others 2021-05-31 11:39:09 +03:00
catborise
508e3609be lint with black python. convert f style strings to old one. some small fixes 2020-11-05 12:34:31 +03:00
Real-Gecko
01043ba8a8 Templates cleanup 2020-10-15 20:18:45 +06:00
Real-Gecko
1b3fd9d05e replaced ugettext_lazy with gettext_lazy 2020-10-14 18:27:57 +06:00
Real-Gecko
9a75ceb0e5 Replaced __unicode__ with __str__ for models 2020-06-15 12:57:17 +06:00
Real-Gecko
cfd739778c Added missing migrations 2020-06-15 12:38:44 +06:00
catborise
e97d592e51 fix some messages, add translation for some keywords, update tr locale file 2020-06-12 14:46:17 +03:00
catborise
e46bb99b3b fix typos and rearrange imports & add new lines EOF 2020-06-04 15:22:55 +03:00
catborise
028ce0c208 urls.py: convert re_path to path 2020-06-04 14:31:37 +03:00
catborise
7538ddab4f Add all settings to appsettings page & Convert settings choices 2020-06-04 12:32:00 +03:00
Real-Gecko
10b6f88dbb Added coverage.py support 2020-05-29 19:37:49 +06:00
Real-Gecko
27f62dff6c Added admin application
- Manage users
- Manage groups
- Manage logs
2020-05-27 18:24:06 +06:00
Real-Gecko
38befa4362 Added django-login-required-middleware
Thus eliminating need for login_requred decorator on every view
2020-05-27 12:43:29 +06:00
catborise
4d40de1b55 Python3 & Django 2.2 Migration - Fix & Updates 2020-03-16 16:59:45 +03:00
catborise
a6f7618854 convert django.core.urlresolver to django.urls. fix i18n. fix identation 2020-01-24 10:09:46 +03:00
catborise
828a271789 pep8 style code corrections 2019-09-10 09:48:31 +03:00
catborise
b18290794e Translate, indentation and typo fixes 2019-07-31 11:03:48 +03:00
catborise
aba92e30b5 x character converted to &times; 2018-08-01 17:18:51 +03:00
Ing. Jan KRCMAR
839b8d420d instance view: added logs section to graphs (renamed graphs -> stats) 2017-12-11 15:07:01 +01:00
Jan Krcmar
6afcd00e2e logs view adds paging ability
settings.LOGS_PER_PAGE controls logs count per page
2016-03-23 10:38:33 +01:00
Retspen
1d22771519 Fixed #7 2015-05-18 22:00:30 +03:00
Retspen
2aa5558df7 Fixed pep8 2015-04-06 10:51:50 +03:00
Retspen
b4e8da8671 Resoved problem with app template 2015-04-02 16:20:46 +03:00
Retspen
ea41412aac Move tempates 2015-04-02 11:48:40 +03:00
Retspen
1f68e8c5ed Added migration 2015-03-25 11:36:37 +02:00
Retspen
1642100ef4 Added log func and fix buttons on instance page 2015-03-18 15:48:29 +02:00
Retspen
90d8dd5729 Think about new macbook 2015-03-16 16:51:51 +02:00
Retspen
5ba82e29aa Little fix user page 2015-03-16 15:46:44 +02:00
Retspen
5960e94da5 Add logs and block for templates 2015-03-03 11:34:09 +02:00