dn-scribe commited on
Commit
31bf37f
·
1 Parent(s): bfdb0ef

per user log management

Browse files
Files changed (3) hide show
  1. templates/logs.html +5 -5
  2. todo.md +4 -4
  3. web/routes.py +59 -12
templates/logs.html CHANGED
@@ -20,7 +20,7 @@
20
  </button>
21
  <button class="btn btn-outline-danger" onclick="confirmDeleteAllLogs()">
22
  <i data-feather="trash-2" class="me-1"></i>
23
- Delete All
24
  </button>
25
  </div>
26
  </div>
@@ -179,22 +179,22 @@
179
  <div class="modal-header">
180
  <h5 class="modal-title text-danger">
181
  <i data-feather="alert-triangle" class="me-2"></i>
182
- Delete All Logs
183
  </h5>
184
  <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
185
  </div>
186
  <div class="modal-body">
187
- <p>Are you sure you want to delete <strong>all logs</strong>? This action cannot be undone.</p>
188
  <div class="alert alert-danger">
189
  <i data-feather="alert-circle" class="me-2"></i>
190
- This will permanently delete all system logs from the database.
191
  </div>
192
  </div>
193
  <div class="modal-footer">
194
  <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
195
  <button type="button" class="btn btn-danger" onclick="deleteAllLogs()">
196
  <i data-feather="trash-2" class="me-1"></i>
197
- Delete All Logs
198
  </button>
199
  </div>
200
  </div>
 
20
  </button>
21
  <button class="btn btn-outline-danger" onclick="confirmDeleteAllLogs()">
22
  <i data-feather="trash-2" class="me-1"></i>
23
+ {% if current_user and current_user.username == 'admin' %}Delete All Logs{% else %}Delete My Logs{% endif %}
24
  </button>
25
  </div>
26
  </div>
 
179
  <div class="modal-header">
180
  <h5 class="modal-title text-danger">
181
  <i data-feather="alert-triangle" class="me-2"></i>
182
+ {% if current_user and current_user.username == 'admin' %}Delete All Logs{% else %}Delete My Logs{% endif %}
183
  </h5>
184
  <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
185
  </div>
186
  <div class="modal-body">
187
+ <p>Are you sure you want to delete {% if current_user and current_user.username == 'admin' %}<strong>all logs</strong>{% else %}<strong>all your logs</strong>{% endif %}? This action cannot be undone.</p>
188
  <div class="alert alert-danger">
189
  <i data-feather="alert-circle" class="me-2"></i>
190
+ This will permanently delete {% if current_user and current_user.username == 'admin' %}all system logs{% else %}all your logs{% endif %} from the database.
191
  </div>
192
  </div>
193
  <div class="modal-footer">
194
  <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
195
  <button type="button" class="btn btn-danger" onclick="deleteAllLogs()">
196
  <i data-feather="trash-2" class="me-1"></i>
197
+ {% if current_user and current_user.username == 'admin' %}Delete All Logs{% else %}Delete My Logs{% endif %}
198
  </button>
199
  </div>
200
  </div>
todo.md CHANGED
@@ -2,9 +2,8 @@ Analyze use cases:
2
 
3
 
4
  What is the value to be extracted from the UX?
5
- - Just management and tracking of the attestation store, not a webapp
6
- - Show policy results
7
- - Show product table with policy result tags
8
  - SBOM app: search, vulns, etc.
9
  - Discovery app
10
  - verify signature + support PKI
@@ -16,4 +15,5 @@ Tasks:
16
  - Fix attestation table: let choose labels/context fields to use. Show the whole Json of the attestation in a JSON viewer
17
  - Implement/Fix deduplication
18
  - download attestation: preserve file name if possible (for UX generated)
19
- - Webhooks/attestation datamodel: add link for downloading the attestation from the app (better --> in data model)
 
 
2
 
3
 
4
  What is the value to be extracted from the UX?
5
+ - Just management and tracking of the attestation store, not a webapp: **Done**
6
+ - Show policy results, Show product table with policy result tags
 
7
  - SBOM app: search, vulns, etc.
8
  - Discovery app
9
  - verify signature + support PKI
 
15
  - Fix attestation table: let choose labels/context fields to use. Show the whole Json of the attestation in a JSON viewer
16
  - Implement/Fix deduplication
17
  - download attestation: preserve file name if possible (for UX generated)
18
+ - Webhooks/attestation datamodel: add link for downloading the attestation from the app (better --> in data model) - **No need, we have the ID and there is the evidence API**
19
+ - Remove filter automatically logs: don't show app logs in the UI (post and get logs)
web/routes.py CHANGED
@@ -243,6 +243,11 @@ def logs():
243
 
244
  # Build query
245
  query = SystemLog.query
 
 
 
 
 
246
 
247
  if severity:
248
  try:
@@ -325,9 +330,18 @@ def log_detail(log_id):
325
  """Return a single log entry as JSON by ID"""
326
  if 'user_id' not in session:
327
  return jsonify({'error': 'Unauthorized'}), 401
 
 
 
 
 
328
  log = SystemLog.query.get(log_id)
329
  if not log:
330
  return jsonify({'error': 'Log not found'}), 404
 
 
 
 
331
  def log_to_dict(log):
332
  return {
333
  "id": log.id,
@@ -354,27 +368,44 @@ def log_stats():
354
  if 'user_id' not in session:
355
  return redirect(url_for('web.login'))
356
 
 
 
 
357
  try:
 
 
 
 
 
358
  # Get log counts by severity
359
  severity_stats = db.session.query(
360
  SystemLog.severity,
361
  db.func.count(SystemLog.id).label('count')
362
- ).group_by(SystemLog.severity).all()
 
 
 
363
 
364
  # Get log counts by event type
365
  event_stats = db.session.query(
366
  SystemLog.event_type,
367
  db.func.count(SystemLog.id).label('count')
368
- ).group_by(SystemLog.event_type).limit(10).all()
 
 
 
369
 
370
  # Get log counts by app name
371
  app_stats = db.session.query(
372
  SystemLog.app_name,
373
  db.func.count(SystemLog.id).label('count')
374
- ).group_by(SystemLog.app_name).limit(10).all()
 
 
 
375
 
376
  # Total logs
377
- total_logs = SystemLog.query.count()
378
 
379
  return jsonify({
380
  'total_logs': total_logs,
@@ -395,20 +426,29 @@ def log_stats():
395
  @web_bp.route('/ux/logs/delete', methods=['POST'])
396
  @login_required
397
  def delete_logs():
398
- """Delete all logs endpoint"""
399
  if 'user_id' not in session:
400
  return jsonify({'error': 'Unauthorized'}), 401
401
 
 
 
 
402
  try:
403
- # Delete all logs
404
- count = SystemLog.query.delete()
 
 
 
 
 
 
405
  db.session.commit()
406
 
407
  log_event(
408
  severity=6,
409
- message=f"All logs deleted by user (count: {count})",
410
  event_type="logs_deleted",
411
- user_id=session.get('user_id'),
412
  source_ip=request.remote_addr
413
  )
414
 
@@ -424,7 +464,7 @@ def delete_logs():
424
  severity=3,
425
  message=f"Failed to delete logs: {str(e)}",
426
  event_type="delete_logs_error",
427
- user_id=session.get('user_id')
428
  )
429
  return jsonify({'error': str(e)}), 500
430
 
@@ -438,6 +478,9 @@ def status():
438
  # Get system information
439
  config = current_app.config.get('STORAGE_CONFIG')
440
 
 
 
 
441
  stats = {
442
  'storage_type': config.STORAGE_TYPE if config else 'Unknown',
443
  'total_users': User.query.count(),
@@ -446,8 +489,12 @@ def status():
446
  'total_logs': SystemLog.query.count(),
447
  }
448
 
449
- # Get recent activity
450
- recent_logs = SystemLog.query.order_by(
 
 
 
 
451
  SystemLog.timestamp.desc()
452
  ).limit(10).all()
453
 
 
243
 
244
  # Build query
245
  query = SystemLog.query
246
+
247
+ # Filter by user_id unless user is admin
248
+ user_id = session['user_id']
249
+ if not is_admin_user_web(user_id):
250
+ query = query.filter(SystemLog.user_id == user_id)
251
 
252
  if severity:
253
  try:
 
330
  """Return a single log entry as JSON by ID"""
331
  if 'user_id' not in session:
332
  return jsonify({'error': 'Unauthorized'}), 401
333
+
334
+ user_id = session['user_id']
335
+ is_admin = is_admin_user_web(user_id)
336
+
337
+ # Get the log
338
  log = SystemLog.query.get(log_id)
339
  if not log:
340
  return jsonify({'error': 'Log not found'}), 404
341
+
342
+ # Check if user has permission to view this log
343
+ if not is_admin and log.user_id != user_id:
344
+ return jsonify({'error': 'You do not have permission to view this log'}), 403
345
  def log_to_dict(log):
346
  return {
347
  "id": log.id,
 
368
  if 'user_id' not in session:
369
  return redirect(url_for('web.login'))
370
 
371
+ user_id = session['user_id']
372
+ is_admin = is_admin_user_web(user_id)
373
+
374
  try:
375
+ # Base queries - filter by user_id unless admin
376
+ base_query = SystemLog.query
377
+ if not is_admin:
378
+ base_query = base_query.filter_by(user_id=user_id)
379
+
380
  # Get log counts by severity
381
  severity_stats = db.session.query(
382
  SystemLog.severity,
383
  db.func.count(SystemLog.id).label('count')
384
+ )
385
+ if not is_admin:
386
+ severity_stats = severity_stats.filter(SystemLog.user_id == user_id)
387
+ severity_stats = severity_stats.group_by(SystemLog.severity).all()
388
 
389
  # Get log counts by event type
390
  event_stats = db.session.query(
391
  SystemLog.event_type,
392
  db.func.count(SystemLog.id).label('count')
393
+ )
394
+ if not is_admin:
395
+ event_stats = event_stats.filter(SystemLog.user_id == user_id)
396
+ event_stats = event_stats.group_by(SystemLog.event_type).limit(10).all()
397
 
398
  # Get log counts by app name
399
  app_stats = db.session.query(
400
  SystemLog.app_name,
401
  db.func.count(SystemLog.id).label('count')
402
+ )
403
+ if not is_admin:
404
+ app_stats = app_stats.filter(SystemLog.user_id == user_id)
405
+ app_stats = app_stats.group_by(SystemLog.app_name).limit(10).all()
406
 
407
  # Total logs
408
+ total_logs = base_query.count()
409
 
410
  return jsonify({
411
  'total_logs': total_logs,
 
426
  @web_bp.route('/ux/logs/delete', methods=['POST'])
427
  @login_required
428
  def delete_logs():
429
+ """Delete logs endpoint"""
430
  if 'user_id' not in session:
431
  return jsonify({'error': 'Unauthorized'}), 401
432
 
433
+ user_id = session['user_id']
434
+ is_admin = is_admin_user_web(user_id)
435
+
436
  try:
437
+ # Delete logs - if admin delete all, otherwise only user's logs
438
+ if is_admin:
439
+ count = SystemLog.query.delete()
440
+ message = f"All logs deleted by admin (count: {count})"
441
+ else:
442
+ count = SystemLog.query.filter_by(user_id=user_id).delete()
443
+ message = f"User logs deleted by user (count: {count})"
444
+
445
  db.session.commit()
446
 
447
  log_event(
448
  severity=6,
449
+ message=message,
450
  event_type="logs_deleted",
451
+ user_id=user_id,
452
  source_ip=request.remote_addr
453
  )
454
 
 
464
  severity=3,
465
  message=f"Failed to delete logs: {str(e)}",
466
  event_type="delete_logs_error",
467
+ user_id=user_id
468
  )
469
  return jsonify({'error': str(e)}), 500
470
 
 
478
  # Get system information
479
  config = current_app.config.get('STORAGE_CONFIG')
480
 
481
+ user_id = session['user_id']
482
+ is_admin = is_admin_user_web(user_id)
483
+
484
  stats = {
485
  'storage_type': config.STORAGE_TYPE if config else 'Unknown',
486
  'total_users': User.query.count(),
 
489
  'total_logs': SystemLog.query.count(),
490
  }
491
 
492
+ # Get recent activity - filter by user unless admin
493
+ log_query = SystemLog.query
494
+ if not is_admin:
495
+ log_query = log_query.filter_by(user_id=user_id)
496
+
497
+ recent_logs = log_query.order_by(
498
  SystemLog.timestamp.desc()
499
  ).limit(10).all()
500