CSAI2026 labs: Lab-2..Lab-6 (Practical + Solution, data), Module-2..Module-6 notebooks and datasets

This commit is contained in:
mikrotik
2026-10-12 19:16:14 +07:00
commit 2fefa615cc
184 changed files with 1016761 additions and 0 deletions
@@ -0,0 +1,242 @@
{
"cells": [
{
"cell_type": "markdown",
"id": "06f7188c",
"metadata": {},
"source": [
"# Module 2 — Lab 3: Data Structures and Raw Log Analysis\n",
" \n",
"**Topics:** list, tuple, dictionary, set, parsing\n",
"\n",
"\n",
"> **Solution version:** This notebook contains the complete solution. Run the cells in order and compare the results with your Lab notebook.\n"
]
},
{
"cell_type": "markdown",
"id": "67ad00e0",
"metadata": {},
"source": [
"## Input data\n",
"\n",
"Each log line contains four comma-separated fields: `timestamp,source_ip,username,status`.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4b49fc55",
"metadata": {},
"outputs": [],
"source": [
"raw_logs = [\n",
" \"2026-09-01T08:00:00Z,203.0.113.55,alice,SUCCESS\",\n",
" \"2026-09-01T08:01:00Z,198.51.100.14,admin,FAILED\",\n",
" \"2026-09-01T08:01:20Z,198.51.100.14,root,FAILED\",\n",
" \"2026-09-01T08:02:00Z,192.0.2.88,bob,SUCCESS\",\n",
" \"2026-09-01T08:02:30Z,198.51.100.14,guest,FAILED\",\n",
" \"2026-09-01T08:03:00Z,192.0.2.99,carol,FAILED\",\n",
"]\n",
"\n",
"critical_fields = (\"timestamp\", \"source_ip\", \"username\", \"status\")\n",
"blocked_ips = {\"198.51.100.14\", \"203.0.113.200\"}\n",
"\n",
"print(f\"Rows: {len(raw_logs)}\")\n",
"print(\"Critical fields:\", critical_fields)\n"
]
},
{
"cell_type": "markdown",
"id": "3f8fcb17",
"metadata": {
"tags": [
"exercise"
]
},
"source": [
"## 1. Convert one log line into a dictionary\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "47d1eb8b",
"metadata": {
"tags": [
"solution"
]
},
"outputs": [],
"source": [
"def parse_log_line(line):\n",
" timestamp, source_ip, username, status = line.split(\",\")\n",
" return {\n",
" \"timestamp\": timestamp,\n",
" \"source_ip\": source_ip,\n",
" \"username\": username.lower(),\n",
" \"status\": status.upper(),\n",
" }\n",
"\n",
"\n",
"sample_event = parse_log_line(raw_logs[0])\n",
"print(sample_event)\n"
]
},
{
"cell_type": "markdown",
"id": "56f0258d",
"metadata": {
"tags": [
"exercise"
]
},
"source": [
"## 2. Create an event list and a set of unique IP addresses\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a8c8af5e",
"metadata": {
"tags": [
"solution"
]
},
"outputs": [],
"source": [
"events = [parse_log_line(line) for line in raw_logs]\n",
"unique_ips = {event[\"source_ip\"] for event in events}\n",
"\n",
"print(\"Unique IPs:\", sorted(unique_ips))\n",
"print(\"Number of unique IPs:\", len(unique_ips))\n"
]
},
{
"cell_type": "markdown",
"id": "7651a31c",
"metadata": {
"tags": [
"exercise"
]
},
"source": [
"## 3. Count failed logins with a dictionary\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "0c0a3675",
"metadata": {
"tags": [
"solution"
]
},
"outputs": [],
"source": [
"failed_by_ip = {}\n",
"\n",
"for event in events:\n",
" if event[\"status\"] != \"FAILED\":\n",
" continue\n",
" ip = event[\"source_ip\"]\n",
" failed_by_ip[ip] = failed_by_ip.get(ip, 0) + 1\n",
"\n",
"print(failed_by_ip)\n"
]
},
{
"cell_type": "markdown",
"id": "21436c12",
"metadata": {
"tags": [
"exercise"
]
},
"source": [
"## 4. Combine dictionaries and sets to create alerts\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "11954df9",
"metadata": {
"tags": [
"solution"
]
},
"outputs": [],
"source": [
"alerts = []\n",
"\n",
"for ip, count in failed_by_ip.items():\n",
" if count >= 3 or ip in blocked_ips:\n",
" alerts.append({\n",
" \"source_ip\": ip,\n",
" \"failed_attempts\": count,\n",
" \"blocked\": ip in blocked_ips,\n",
" })\n",
"\n",
"print(alerts)\n"
]
},
{
"cell_type": "markdown",
"id": "b18d5731",
"metadata": {},
"source": [
"## Self-check\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d30adfba",
"metadata": {},
"outputs": [],
"source": [
"assert sample_event[\"username\"] == \"alice\"\n",
"assert len(events) == 6\n",
"assert unique_ips == {\"203.0.113.55\", \"198.51.100.14\", \"192.0.2.88\", \"192.0.2.99\"}\n",
"assert failed_by_ip[\"198.51.100.14\"] == 3\n",
"assert alerts == [{\"source_ip\": \"198.51.100.14\", \"failed_attempts\": 3, \"blocked\": True}]\n",
"print(\"✓ Lab 3 completed\")\n"
]
},
{
"cell_type": "markdown",
"id": "55d97609",
"metadata": {},
"source": [
"## Reflection questions\n",
"\n",
"- Why is a `set` suitable for storing unique IP addresses or a blocklist?\n",
"- Why is a `tuple` suitable for field names that should not change?\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.6"
}
},
"nbformat": 4,
"nbformat_minor": 5
}