From c3f477788ea0abde1acaca9c81d3dc5c2295545e Mon Sep 17 00:00:00 2001 From: Zuev Date: Thu, 30 Jul 2026 00:28:02 +0300 Subject: [PATCH] =?UTF-8?q?=D0=A3=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=83=D1=8F=D0=B7=D0=B2=D0=B8=D0=BC=D0=BE=D1=81?= =?UTF-8?q?=D1=82=D0=B8=20backend-=D0=BE=D0=B1=D1=80=D0=B0=D0=B7=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 2 +- backend/Dockerfile | 5 +- backend/pom.xml | 7 +- .../DepartmentWorkspaceControllerTest.java | 15 +- .../TeacherSubjectControllerTest.java | 15 +- docs/ARCHITECTURE.md | 4 +- docs/INFRASTRUCTURE.md | 4 +- docs/README.md | 2 +- graphify-out/.graphify_learning.json | 180 +++++++++++++----- ...€ить_опубликованные_образы__backend_trivy_hig.md | 25 +++ graphify-out/reflections/LESSONS.md | 14 +- scripts/check-artifact-pinning.sh | 10 + scripts/test-artifact-pinning.sh | 8 + 13 files changed, 226 insertions(+), 65 deletions(-) create mode 100644 graphify-out/memory/query_20260729_212726_проверить_опубликованные_образы__backend_trivy_hig.md diff --git a/AGENTS.md b/AGENTS.md index 4b00695..ba3b8a7 100755 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,7 +3,7 @@ ## Обзор проекта Проект представляет собой систему управления университетским расписанием. -- **Backend**: Java 17, Spring Boot 3.2.5 (Мультитенантная архитектура: отдельная БД для каждого клиента) +- **Backend**: Java 17, Spring Boot 3.5.16 (Мультитенантная архитектура: отдельная БД для каждого клиента) - **Frontend**: Vanilla JavaScript + HTML/CSS (без фреймворков) - **Database**: PostgreSQL (множество БД, управляются через Flyway) - **Локальный URL**: localhost:80 diff --git a/backend/Dockerfile b/backend/Dockerfile index 234cf97..6966c06 100755 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -16,7 +16,10 @@ RUN mvn org.apache.maven.plugins:maven-dependency-plugin:3.6.1:copy \ FROM eclipse-temurin:17-jre-alpine@sha256:02320dd4ce20e243dfb915c686089cf9315c763084fafbb12d5c9993aee18b57 -# Best practice: run as a non-root user +# Устанавливаем исправления безопасности, опубликованные после сборки базового образа. +RUN apk upgrade --no-cache + +# Запускаем приложение от непривилегированного пользователя. RUN addgroup -S spring && adduser -S spring -G spring USER spring:spring diff --git a/backend/pom.xml b/backend/pom.xml index 4f10d8a..c1ab93b 100755 --- a/backend/pom.xml +++ b/backend/pom.xml @@ -7,7 +7,7 @@ org.springframework.boot spring-boot-starter-parent - 3.2.5 + 3.5.16 @@ -18,6 +18,7 @@ 17 + 42.7.12 @@ -44,6 +45,10 @@ org.flywaydb flyway-core + + org.flywaydb + flyway-database-postgresql + org.postgresql postgresql diff --git a/backend/src/test/java/com/magistr/app/controller/DepartmentWorkspaceControllerTest.java b/backend/src/test/java/com/magistr/app/controller/DepartmentWorkspaceControllerTest.java index d37b63f..914f76c 100644 --- a/backend/src/test/java/com/magistr/app/controller/DepartmentWorkspaceControllerTest.java +++ b/backend/src/test/java/com/magistr/app/controller/DepartmentWorkspaceControllerTest.java @@ -15,6 +15,7 @@ import com.magistr.app.repository.DepartmentRepository; import com.magistr.app.repository.TeacherCreationRequestRepository; import com.magistr.app.repository.TeacherDepartmentAssignmentRepository; import com.magistr.app.repository.UserRepository; +import com.magistr.app.service.BusinessTimeService; import com.magistr.app.service.ScheduleQueryService; import com.magistr.app.service.SubjectImportService; import com.magistr.app.service.TeacherDepartmentService; @@ -22,7 +23,10 @@ import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; +import java.time.Clock; +import java.time.Instant; import java.time.LocalDate; +import java.time.ZoneOffset; import java.util.List; import java.util.Map; import java.util.Optional; @@ -34,6 +38,12 @@ import static org.mockito.Mockito.when; class DepartmentWorkspaceControllerTest { + private static final LocalDate TODAY = LocalDate.of(2026, 7, 29); + private static final BusinessTimeService BUSINESS_TIME = new BusinessTimeService( + Clock.fixed(Instant.parse("2026-07-29T09:00:00Z"), ZoneOffset.UTC), + ZoneOffset.UTC + ); + @AfterEach void clearAuthContext() { AuthContext.clear(); @@ -71,7 +81,7 @@ class DepartmentWorkspaceControllerTest { TeacherDepartmentService teacherDepartmentService = mock(TeacherDepartmentService.class); User assignedTeacher = user(10L, "assigned", "Петров Препод Петрович", 2L); User directTeacher = user(11L, "direct", "Препод Тест Тестович", 1L); - when(teacherDepartmentService.findTeachersForDepartmentAtDate(1L, LocalDate.now())) + when(teacherDepartmentService.findTeachersForDepartmentAtDate(1L, TODAY)) .thenReturn(List.of(directTeacher, assignedTeacher)); DepartmentWorkspaceController controller = new DepartmentWorkspaceController( mock(SubjectRepository.class), @@ -82,7 +92,8 @@ class DepartmentWorkspaceControllerTest { mock(TeacherCreationRequestRepository.class), mock(ScheduleQueryService.class), teacherDepartmentService, - mock(SubjectImportService.class) + mock(SubjectImportService.class), + BUSINESS_TIME ); List teachers = controller.getTeachers(1L); diff --git a/backend/src/test/java/com/magistr/app/controller/TeacherSubjectControllerTest.java b/backend/src/test/java/com/magistr/app/controller/TeacherSubjectControllerTest.java index 837cece..64e4bcb 100644 --- a/backend/src/test/java/com/magistr/app/controller/TeacherSubjectControllerTest.java +++ b/backend/src/test/java/com/magistr/app/controller/TeacherSubjectControllerTest.java @@ -9,12 +9,15 @@ import com.magistr.app.model.User; import com.magistr.app.repository.SubjectRepository; import com.magistr.app.repository.TeacherSubjectRepository; import com.magistr.app.repository.UserRepository; +import com.magistr.app.service.BusinessTimeService; import com.magistr.app.service.TeacherDepartmentService; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; -import java.time.LocalDate; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneOffset; import java.util.Map; import java.util.Optional; @@ -25,6 +28,11 @@ import static org.mockito.Mockito.when; class TeacherSubjectControllerTest { + private static final BusinessTimeService BUSINESS_TIME = new BusinessTimeService( + Clock.fixed(Instant.parse("2026-07-29T09:00:00Z"), ZoneOffset.UTC), + ZoneOffset.UTC + ); + @AfterEach void clearAuthContext() { AuthContext.clear(); @@ -46,13 +54,14 @@ class TeacherSubjectControllerTest { when(teacherDepartmentService.hasAssignmentAtDate( teacher.getId(), 1L, - LocalDate.now() + BUSINESS_TIME.today() )).thenReturn(true); TeacherSubjectController controller = new TeacherSubjectController( teacherSubjectRepository, userRepository, subjectRepository, - teacherDepartmentService + teacherDepartmentService, + BUSINESS_TIME ); AuthContext.setCurrentUser(new AuthenticatedUser(1L, "кафедра", Role.DEPARTMENT, 1L)); diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 3b37e94..cd4be95 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -6,7 +6,7 @@ graph TD Client["🌐 Браузер"] -->|HTTPS| Caddy["Caddy Proxy"] Caddy -->|:80| Frontend["Frontend
(Apache httpd + строгий CSP)"] - Caddy -->|/api/*| Backend["Backend
(Spring Boot 3.2.5)"] + Caddy -->|/api/*| Backend["Backend
(Spring Boot 3.5.16)"] Backend --> TenantRouter{"TenantRoutingDataSource"} TenantRouter -->|swsu.zuev.company| DB1["PostgreSQL
swsu_db"] @@ -27,7 +27,7 @@ graph TD - **JS-модули:** Vanilla JavaScript с ES6 Modules (`import`/`export`) - **Browser security:** same-origin runtime-ресурсы и CSP без `unsafe-inline`/`unsafe-eval` -### Backend (Spring Boot 3.2.5) +### Backend (Spring Boot 3.5.16) - **Тип:** REST API сервер - **Язык:** Java 17 - **Порт:** 8080 (внутренний) diff --git a/docs/INFRASTRUCTURE.md b/docs/INFRASTRUCTURE.md index 9bf1986..c5da073 100644 --- a/docs/INFRASTRUCTURE.md +++ b/docs/INFRASTRUCTURE.md @@ -86,7 +86,9 @@ Backend собирается через multi-stage сборку Maven: 1. Этап сборки: `maven:3.9.9-eclipse-temurin-17@sha256:f58d59b...` → `mvn package` 2. OpenTelemetry Java Agent `2.28.1` загружается как фиксированный Maven-артефакт и проверяется по закреплённому SHA-256 -3. Этап запуска: `eclipse-temurin:17-jre-alpine@sha256:02320dd4...` → `java -jar app.jar` +3. Этап запуска: `eclipse-temurin:17-jre-alpine@sha256:02320dd4...`; перед добавлением + непривилегированного пользователя устанавливаются доступные исправления Alpine через + `apk upgrade --no-cache`, затем выполняется `java -jar app.jar` ### Dockerfile (Frontend) diff --git a/docs/README.md b/docs/README.md index 6046bc0..bd314c7 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,7 +13,7 @@ | Компонент | Технология | |-----------|-----------| -| **Backend** | Java 17, Spring Boot 3.2.5 | +| **Backend** | Java 17, Spring Boot 3.5.16 | | **Frontend** | Vanilla JavaScript (ES6 Modules) + HTML/CSS | | **База данных** | PostgreSQL (через Flyway миграции) | | **Контейнеризация** | Docker, Docker Compose | diff --git a/graphify-out/.graphify_learning.json b/graphify-out/.graphify_learning.json index 298e703..bdbf2fb 100644 --- a/graphify-out/.graphify_learning.json +++ b/graphify-out/.graphify_learning.json @@ -1,11 +1,37 @@ { - "generated_at": "2026-07-29T20:02:59.230356+00:00", + "generated_at": "2026-07-29T21:00:52.911357+00:00", "nodes": { - "_gitea_workflows_docker_build_build_and_push_docker_images": { - "code_fingerprint": "80373e004c326a786715725be21ddb9214b6ff382a02cb829acad1bb9c9098f8", - "label": "Workflow сборки и публикации Docker-образов", - "last": "2026-07-29T19:59:04.551881+00:00", + "_gitea_workflows_docker_build_backend_image_pipeline": { + "code_fingerprint": "672f3effb2b85afa48bca601809662a5567dc0d57a24b224d4c7f1624899b222", + "label": "Pipeline backend-образа", + "last": "2026-07-29T20:38:53.488440+00:00", "provenance": [ + { + "date": "2026-07-29T20:38:53.488440+00:00", + "outcome": "useful", + "q": "The goal you specified requires a project to execute but there is no POM in this directory (/workspace)." + } + ], + "score": 0.999647225, + "source_file": ".gitea/workflows/docker-build.yaml", + "status": "tentative", + "uses": 1 + }, + "_gitea_workflows_docker_build_build_and_push_docker_images": { + "code_fingerprint": "672f3effb2b85afa48bca601809662a5567dc0d57a24b224d4c7f1624899b222", + "label": "Workflow сборки и публикации Docker-образов", + "last": "2026-07-29T20:38:53.488440+00:00", + "provenance": [ + { + "date": "2026-07-29T20:38:53.488440+00:00", + "outcome": "useful", + "q": "The goal you specified requires a project to execute but there is no POM in this directory (/workspace)." + }, + { + "date": "2026-07-29T20:12:38.880629+00:00", + "outcome": "useful", + "q": "сам можешь выполнить эти действия?" + }, { "date": "2026-07-29T19:59:04.551881+00:00", "outcome": "useful", @@ -17,10 +43,42 @@ "q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?" } ], - "score": 1.999355769, + "score": 3.996372989, "source_file": ".gitea/workflows/docker-build.yaml", "status": "preferred", - "uses": 2 + "uses": 4 + }, + "_gitea_workflows_docker_build_deploy_to_k8s": { + "code_fingerprint": "672f3effb2b85afa48bca601809662a5567dc0d57a24b224d4c7f1624899b222", + "label": "Job деплоя в Kubernetes", + "last": "2026-07-29T20:12:38.880629+00:00", + "provenance": [ + { + "date": "2026-07-29T20:12:38.880629+00:00", + "outcome": "useful", + "q": "сам можешь выполнить эти действия?" + } + ], + "score": 0.999226384, + "source_file": ".gitea/workflows/docker-build.yaml", + "status": "tentative", + "uses": 1 + }, + "_gitea_workflows_docker_build_frontend_image_pipeline": { + "code_fingerprint": "672f3effb2b85afa48bca601809662a5567dc0d57a24b224d4c7f1624899b222", + "label": "Pipeline frontend-образа", + "last": "2026-07-29T20:38:53.488440+00:00", + "provenance": [ + { + "date": "2026-07-29T20:38:53.488440+00:00", + "outcome": "useful", + "q": "The goal you specified requires a project to execute but there is no POM in this directory (/workspace)." + } + ], + "score": 0.999647225, + "source_file": ".gitea/workflows/docker-build.yaml", + "status": "tentative", + "uses": 1 }, "backend_src_main_java_com_magistr_app_config_auth_authorizationinterceptor_authorizationinterceptor": { "code_fingerprint": "70b01b3fa22e058ee997250c52cc0affee54ab37aa5f8cc7eb74411487f1bbbf", @@ -43,7 +101,7 @@ "q": "Почему RequireRoles связывает множество контроллеров, моделей и сервисов как cross-community bridge?" } ], - "score": 1.861135007, + "score": 1.859406956, "source_file": "backend/src/main/java/com/magistr/app/config/auth/AuthorizationInterceptor.java", "status": "preferred", "uses": 3 @@ -59,7 +117,7 @@ "q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?" } ], - "score": 0.661231273, + "score": 0.660617324, "source_file": "backend/src/main/java/com/magistr/app/config/auth/JwtTokenService.java", "status": "tentative", "uses": 1 @@ -75,7 +133,7 @@ "q": "Почему RequireRoles связывает множество контроллеров, моделей и сервисов как cross-community bridge?" } ], - "score": 0.556344408, + "score": 0.555827846, "source_file": "backend/src/main/java/com/magistr/app/config/auth/RequireRoles.java", "status": "tentative", "uses": 1 @@ -91,7 +149,7 @@ "q": "Как безопасно обновлять tenant DataSource без потери рабочего подключения?" } ], - "score": 0.676664767, + "score": 0.676036488, "source_file": "backend/src/main/java/com/magistr/app/config/DataInitializer.java", "status": "tentative", "uses": 1 @@ -107,7 +165,7 @@ "q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'" } ], - "score": 0.643559327, + "score": 0.642961786, "source_file": "backend/src/main/java/com/magistr/app/config/tenant/ConfigMapUpdater.java", "status": "tentative", "uses": 1 @@ -123,7 +181,7 @@ "q": "Как безопасно заменить tenant DataSource без потери рабочего подключения?" } ], - "score": 0.676550037, + "score": 0.675921865, "source_file": "backend/src/main/java/com/magistr/app/config/tenant/TenantConfig.java", "status": "tentative", "uses": 1 @@ -149,7 +207,7 @@ "q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'" } ], - "score": 1.99677413, + "score": 1.994920139, "source_file": "backend/src/main/java/com/magistr/app/config/tenant/TenantConfigWatcher.java", "status": "preferred", "uses": 3 @@ -175,7 +233,7 @@ "q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?" } ], - "score": 2.014446076, + "score": 2.012575677, "source_file": "backend/src/main/java/com/magistr/app/config/tenant/TenantRoutingDataSource.java", "status": "preferred", "uses": 3 @@ -191,7 +249,7 @@ "q": "Почему в выборе аудитории показаны корпус и этаж?" } ], - "score": 0.831862505, + "score": 0.831090126, "source_file": "backend/src/main/java/com/magistr/app/controller/ClassroomController.java", "status": "tentative", "uses": 1 @@ -207,7 +265,7 @@ "q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?" } ], - "score": 0.661231273, + "score": 0.660617324, "source_file": "backend/src/main/java/com/magistr/app/controller/DatabaseController.java", "status": "tentative", "uses": 1 @@ -228,7 +286,7 @@ "q": "Как безопасно заменить tenant DataSource без потери рабочего подключения?" } ], - "score": 1.353214804, + "score": 1.351958353, "source_file": "backend/src/main/java/com/magistr/app/controller/DatabaseController.java", "status": "preferred", "uses": 2 @@ -244,7 +302,7 @@ "q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'" } ], - "score": 0.643559327, + "score": 0.642961786, "source_file": "backend/src/main/java/com/magistr/app/controller/GlobalExceptionHandler.java", "status": "tentative", "uses": 1 @@ -265,7 +323,7 @@ "q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?" } ], - "score": 1.492325672, + "score": 1.490940058, "source_file": "backend/src/main/java/com/magistr/app/controller/ScheduleController.java", "status": "preferred", "uses": 2 @@ -281,7 +339,7 @@ "q": "Как безопасно валидировать и сохранять точечные изменения расписания?" } ], - "score": 0.671815777, + "score": 0.671192001, "source_file": "backend/src/main/java/com/magistr/app/controller/ScheduleOverrideController.java", "status": "tentative", "uses": 1 @@ -302,7 +360,7 @@ "q": "проанализируй весь проект на баги и ошибки и дополни '/mnt/HDD/ProjectMagistr/magistr/BUG_REPORT.md'" } ], - "score": 1.319879771, + "score": 1.318654271, "source_file": "backend/src/main/java/com/magistr/app/controller/ScheduleRuleAdminController.java", "status": "preferred", "uses": 2 @@ -318,7 +376,7 @@ "q": "хотим поменять название сервиса, придумай что-то короткое одним словом подходящее по смыслу" } ], - "score": 0.851581632, + "score": 0.850790945, "source_file": "backend/src/main/java/com/magistr/app/model/AcademicCalendar.java", "status": "tentative", "uses": 1 @@ -334,7 +392,7 @@ "q": "Почему в выборе аудитории показаны корпус и этаж?" } ], - "score": 0.831862505, + "score": 0.831090126, "source_file": "backend/src/main/java/com/magistr/app/model/Classroom.java", "status": "tentative", "uses": 1 @@ -350,7 +408,7 @@ "q": "хотим поменять название сервиса, придумай что-то короткое одним словом подходящее по смыслу" } ], - "score": 0.851581632, + "score": 0.850790945, "source_file": "backend/src/main/java/com/magistr/app/model/Department.java", "status": "tentative", "uses": 1 @@ -371,7 +429,7 @@ "q": "Корректны ли inferred-связи вокруг ScheduleRule?" } ], - "score": 1.23328582, + "score": 1.232140722, "source_file": "backend/src/main/java/com/magistr/app/model/ScheduleRule.java", "status": "preferred", "uses": 2 @@ -387,7 +445,7 @@ "q": "Какие связи затрагивает полная валидация правил расписания в исправлении №7?" } ], - "score": 0.676320444, + "score": 0.675692485, "source_file": "backend/src/main/java/com/magistr/app/model/ScheduleRuleSlot.java", "status": "tentative", "uses": 1 @@ -408,7 +466,7 @@ "q": "в дополнительные фильры просмотра расписаний нужно добавить выбор семестра" } ], - "score": 1.682676032, + "score": 1.681113679, "source_file": "backend/src/main/java/com/magistr/app/model/Semester.java", "status": "preferred", "uses": 2 @@ -424,7 +482,7 @@ "q": "хотим поменять название сервиса, придумай что-то короткое одним словом подходящее по смыслу" } ], - "score": 0.851581632, + "score": 0.850790945, "source_file": "backend/src/main/java/com/magistr/app/model/StudentGroup.java", "status": "tentative", "uses": 1 @@ -440,7 +498,7 @@ "q": "Какие связи затрагивает полная валидация правил расписания в исправлении №7?" } ], - "score": 0.676320444, + "score": 0.675692485, "source_file": "backend/src/main/java/com/magistr/app/repository/SemesterRepository.java", "status": "tentative", "uses": 1 @@ -461,7 +519,7 @@ "q": "Как безопасно валидировать и сохранять точечные изменения расписания?" } ], - "score": 1.502910177, + "score": 1.501514735, "source_file": "backend/src/main/java/com/magistr/app/service/ScheduleQueryService.java", "status": "preferred", "uses": 2 @@ -477,7 +535,7 @@ "q": "Корректны ли inferred-связи вокруг ScheduleRule?" } ], - "score": 0.556965376, + "score": 0.556448237, "source_file": "backend/src/test/java/com/magistr/app/model/ScheduleRuleTest.java", "status": "tentative", "uses": 1 @@ -493,7 +551,7 @@ "q": "Какие подсистемы связывают исправления аутентификации, tenant-конфигурации, расписания и инфраструктуры?" } ], - "score": 0.661231273, + "score": 0.660617324, "source_file": "compose.yaml", "status": "tentative", "uses": 1 @@ -509,7 +567,7 @@ "q": "новая схема на проде на удалённом сервере создана через CREATE SCHEMA public. я проверил, давай дальше" } ], - "score": 0.999937245, + "score": 0.99900881, "source_file": "compose.yaml", "status": "tentative", "uses": 1 @@ -525,32 +583,58 @@ "q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?" } ], - "score": 0.999418524, + "score": 0.998490571, "source_file": "docs/DATABASE.md", "status": "tentative", "uses": 1 }, - "docs_infrastructure_jwt_secret_policy": { - "code_fingerprint": "fbce586f3b64dba203d336f5744d9895924e86e122cdde1939c0dec1600e1af1", - "label": "Политика JWT-секрета", - "last": "2026-07-29T19:26:44.188240+00:00", + "docs_infrastructure_gitea_actions_cicd": { + "code_fingerprint": "40b5d07ca2998f186f60fcab44ece5a5bf3ee2ad747acfbe1be3c29d3b7a00f5", + "label": "CI/CD Gitea Actions в инфраструктуре", + "last": "2026-07-29T20:38:53.488440+00:00", "provenance": [ + { + "date": "2026-07-29T20:38:53.488440+00:00", + "outcome": "useful", + "q": "The goal you specified requires a project to execute but there is no POM in this directory (/workspace)." + } + ], + "score": 0.999647225, + "source_file": "docs/INFRASTRUCTURE.md", + "status": "tentative", + "uses": 1 + }, + "docs_infrastructure_jwt_secret_policy": { + "code_fingerprint": "40b5d07ca2998f186f60fcab44ece5a5bf3ee2ad747acfbe1be3c29d3b7a00f5", + "label": "Политика JWT-секрета", + "last": "2026-07-29T20:12:38.880629+00:00", + "provenance": [ + { + "date": "2026-07-29T20:12:38.880629+00:00", + "outcome": "useful", + "q": "сам можешь выполнить эти действия?" + }, { "date": "2026-07-29T19:26:44.188240+00:00", "outcome": "useful", "q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?" } ], - "score": 0.999418524, + "score": 1.997716954, "source_file": "docs/INFRASTRUCTURE.md", - "status": "tentative", - "uses": 1 + "status": "preferred", + "uses": 2 }, "docs_infrastructure_kubernetes_production": { - "code_fingerprint": "fbce586f3b64dba203d336f5744d9895924e86e122cdde1939c0dec1600e1af1", + "code_fingerprint": "40b5d07ca2998f186f60fcab44ece5a5bf3ee2ad747acfbe1be3c29d3b7a00f5", "label": "Production-инфраструктура Kubernetes", - "last": "2026-07-29T19:59:04.551881+00:00", + "last": "2026-07-29T20:12:38.880629+00:00", "provenance": [ + { + "date": "2026-07-29T20:12:38.880629+00:00", + "outcome": "useful", + "q": "сам можешь выполнить эти действия?" + }, { "date": "2026-07-29T19:59:04.551881+00:00", "outcome": "useful", @@ -562,13 +646,13 @@ "q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?" } ], - "score": 1.999355769, + "score": 2.996725764, "source_file": "docs/INFRASTRUCTURE.md", "status": "preferred", - "uses": 2 + "uses": 3 }, "docs_infrastructure_tenants_configmap": { - "code_fingerprint": "fbce586f3b64dba203d336f5744d9895924e86e122cdde1939c0dec1600e1af1", + "code_fingerprint": "40b5d07ca2998f186f60fcab44ece5a5bf3ee2ad747acfbe1be3c29d3b7a00f5", "label": "Tenants ConfigMap", "last": "2026-07-29T19:26:44.188240+00:00", "provenance": [ @@ -578,7 +662,7 @@ "q": "теперь напиши мне инструкцию как это всё выыкатить на прод. у мня уже поднят на проде этот сервис со старой базой данных, но я могу её затереть. ci/cd тоже настроен, по сути я прямо сейчас могу залить это в ветку мейн и оно должно раскататься. каие есть подводные камни после изменений безопасности которые мы внесли?" } ], - "score": 0.999418524, + "score": 0.998490571, "source_file": "docs/INFRASTRUCTURE.md", "status": "tentative", "uses": 1 diff --git a/graphify-out/memory/query_20260729_212726_проверить_опубликованные_образы__backend_trivy_hig.md b/graphify-out/memory/query_20260729_212726_проверить_опубликованные_образы__backend_trivy_hig.md new file mode 100644 index 0000000..94091d1 --- /dev/null +++ b/graphify-out/memory/query_20260729_212726_проверить_опубликованные_образы__backend_trivy_hig.md @@ -0,0 +1,25 @@ +--- +type: "query" +date: "2026-07-29T21:27:26.637336+00:00" +question: "Проверить опубликованные образы: backend Trivy HIGH/CRITICAL scan завершился exitcode 1" +contributor: "graphify" +outcome: "useful" +source_nodes: ["Workflow сборки и публикации Docker-образов", "Pipeline backend-образа", "CI/CD Gitea Actions в инфраструктуре", "SpringBootApplication"] +--- + +# Q: Проверить опубликованные образы: backend Trivy HIGH/CRITICAL scan завершился exitcode 1 + +## Answer + +CI дошёл до сканирования опубликованного backend-образа, поэтому передача исходников в контейнеры уже исправлена. HIGH/CRITICAL находились в устаревших пакетах Alpine и Java-зависимостях Spring Boot 3.2.5. Backend обновлён до Spring Boot 3.5.16, PostgreSQL JDBC закреплён на 42.7.12, для Flyway 11 добавлен flyway-database-postgresql, runtime устанавливает исправления Alpine. Локальный образ прошёл тот же Trivy gate: Alpine 0, app.jar 0, OpenTelemetry agent 0. Полный backend-набор: 300 тестов без ошибок; обязательные CI, frontend, Compose и supply-chain проверки также прошли. + +## Outcome + +- Signal: useful + +## Source Nodes + +- Workflow сборки и публикации Docker-образов +- Pipeline backend-образа +- CI/CD Gitea Actions в инфраструктуре +- SpringBootApplication \ No newline at end of file diff --git a/graphify-out/reflections/LESSONS.md b/graphify-out/reflections/LESSONS.md index cddd6ca..f600f4e 100644 --- a/graphify-out/reflections/LESSONS.md +++ b/graphify-out/reflections/LESSONS.md @@ -1,19 +1,20 @@ # Lessons -_Auto-generated by `graphify reflect` from 14 session memories in graphify-out/memory/. Deterministic; no LLM. Use for orientation — verify before relying, and revisit dead ends if the code has changed since._ +_Auto-generated by `graphify reflect` from 16 session memories in graphify-out/memory/. Deterministic; no LLM. Use for orientation — verify before relying, and revisit dead ends if the code has changed since._ ## Summary -- 13 useful · 1 dead ends · 0 corrected · 0 unmarked +- 15 useful · 1 dead ends · 0 corrected · 0 unmarked ## Lessons **Preferred sources** — corroborated by ≥2 useful results; start here. +- `Workflow сборки и публикации Docker-образов` (4× useful) +- `Production-инфраструктура Kubernetes` (3× useful) - `ScheduleGeneratorService` (3× useful) - `TenantRoutingDataSource` (3× useful) -- `Production-инфраструктура Kubernetes` (2× useful) -- `Workflow сборки и публикации Docker-образов` (2× useful) +- `Политика JWT-секрета` (2× useful) - `TenantConfigWatcher` (3× useful) - `AuthorizationInterceptor` (3× useful) - `Semester` (2× useful) @@ -25,10 +26,13 @@ _Auto-generated by `graphify reflect` from 14 session memories in graphify-out/m **Tentative** — useful in fewer than 2 results; verify before relying. +- `CI/CD Gitea Actions в инфраструктуре` (1× useful) +- `Pipeline backend-образа` (1× useful) +- `Pipeline frontend-образа` (1× useful) +- `Job деплоя в Kubernetes` (1× useful) - `PostgreSQL-сервис Docker Compose` (1× useful) - `Flyway-миграции` (1× useful) - `Tenants ConfigMap` (1× useful) -- `Политика JWT-секрета` (1× useful) - `AcademicCalendar` (1× useful) - `Department` (1× useful) - `StudentGroup` (1× useful) diff --git a/scripts/check-artifact-pinning.sh b/scripts/check-artifact-pinning.sh index 3ab9ca1..a346165 100755 --- a/scripts/check-artifact-pinning.sh +++ b/scripts/check-artifact-pinning.sh @@ -123,6 +123,15 @@ check_downloaded_backend_artifact() { fi } +check_backend_runtime_updates() { + local dockerfile="$PROJECT_ROOT/backend/Dockerfile" + + require_file "$dockerfile" || return + if ! grep -Fq 'RUN apk upgrade --no-cache' "$dockerfile"; then + fail "runtime-образ backend должен устанавливать доступные исправления Alpine" + fi +} + check_testcontainer_images() { local image_catalog="$PROJECT_ROOT/backend/src/test/java/com/magistr/app/testing/TestContainerImages.java" @@ -160,6 +169,7 @@ check_compose_images check_actions check_workflow_gates check_downloaded_backend_artifact +check_backend_runtime_updates check_testcontainer_images check_optional_kubernetes_images diff --git a/scripts/test-artifact-pinning.sh b/scripts/test-artifact-pinning.sh index 90ba9d9..6db1819 100755 --- a/scripts/test-artifact-pinning.sh +++ b/scripts/test-artifact-pinning.sh @@ -37,6 +37,14 @@ if PROJECT_ROOT="$FIXTURE_DIR" bash "$CHECK_SCRIPT" >/dev/null 2>&1; then exit 1 fi +cp "$ROOT_DIR/backend/Dockerfile" "$FIXTURE_DIR/backend/Dockerfile" +sed -i '/RUN apk upgrade --no-cache/d' "$FIXTURE_DIR/backend/Dockerfile" +if PROJECT_ROOT="$FIXTURE_DIR" bash "$CHECK_SCRIPT" >/dev/null 2>&1; then + printf 'Ошибка теста: отсутствие Alpine security updates не было отклонено\n' >&2 + exit 1 +fi + +cp "$ROOT_DIR/backend/Dockerfile" "$FIXTURE_DIR/backend/Dockerfile" cp "$ROOT_DIR/.gitea/workflows/docker-build.yaml" \ "$FIXTURE_DIR/.gitea/workflows/docker-build.yaml" sed -i "/gitea.event_name == 'workflow_dispatch'/d" \