diff --git a/.github/actions/docker/backend/action.yml b/.github/actions/docker/backend/action.yml index 6191d028..73178ece 100644 --- a/.github/actions/docker/backend/action.yml +++ b/.github/actions/docker/backend/action.yml @@ -34,7 +34,7 @@ runs: gradle-encription-key: ${{ inputs.gradle-encryption-key }} - name: Cache Gradle Dependencies - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: | ~/.gradle/caches @@ -51,7 +51,7 @@ runs: shell: bash - name: 🪄 Scan Docker images for vulnerabilities - uses: aquasecurity/trivy-action@0.20.0 + uses: aquasecurity/trivy-action@0.24.0 with: image-ref: ghcr.io/dallay/lyra:latest format: sarif @@ -61,7 +61,7 @@ runs: cache-dir: /tmp/trivy-cache-lyra - name: ⇪ Upload Trivy Scan Report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: trivy-lyra-report path: trivy-lyra-report.sarif diff --git a/.github/actions/docker/frontend/action.yml b/.github/actions/docker/frontend/action.yml index f9eb7e48..2257a6f2 100644 --- a/.github/actions/docker/frontend/action.yml +++ b/.github/actions/docker/frontend/action.yml @@ -85,7 +85,7 @@ runs: password: ${{ inputs.ci_github_token }} - name: Cache Docker Layers - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: /tmp/.buildx-cache key: ${{ runner.os }}-buildx-${{ inputs.target }}-${{ steps.calculate-outputs.outputs.prod_tag }} @@ -107,7 +107,7 @@ runs: cache-to: type=local,dest=/tmp/.buildx-cache,mode=max - name: 🪄 Scan Docker Images for Vulnerabilities - uses: aquasecurity/trivy-action@0.20.0 + uses: aquasecurity/trivy-action@0.24.0 with: image-ref: ${{ steps.calculate-outputs.outputs.repo_name }}:${{ steps.calculate-outputs.outputs.prod_tag }} format: sarif @@ -117,7 +117,7 @@ runs: cache-dir: /tmp/trivy-cache-${{ inputs.target }} - name: ⇪ Upload Trivy Scan Report - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: trivy-${{ inputs.target }}-report-${{ steps.calculate-outputs.outputs.prod_tag }} path: trivy-${{ inputs.target }}-report-${{ steps.calculate-outputs.outputs.prod_tag }}.sarif diff --git a/.junie/guidelines.md b/.junie/guidelines.md new file mode 100644 index 00000000..c62b508d --- /dev/null +++ b/.junie/guidelines.md @@ -0,0 +1,250 @@ +# Lyra Project Development Guidelines + +This document provides essential information for developers working on the Lyra project. + +## Build and Configuration Instructions + +### Prerequisites + +- Java (version specified in `.java-version`) +- Node.js (version specified in `.nvmrc`) +- PNPM (for frontend package management) +- Docker and Docker Compose (for running dependencies) +- GNU Make (for using the provided Makefile targets) + +### Building the Project + +#### Backend (Kotlin/Spring Boot) + +The project uses Gradle as the build tool. The Gradle wrapper (`gradlew`) is included in the repository, so you don't need to install Gradle separately. + +```bash +# Build the entire project +./gradlew build + +# Clean and build +./gradlew clean build + +# Build specific module +./gradlew :apps:backend:build +``` + +You can also use the Makefile for common operations: + +```bash +# Build the project +make build + +# Clean the project +make clean + +# Run tests +make test +``` + +#### Frontend (Node.js) + +The frontend uses PNPM for package management: + +```bash +# Install dependencies +pnpm install + +# Build frontend +pnpm run build +``` + +### Running the Application + +#### Using Docker Compose + +The project includes Docker Compose configuration for running the application and its dependencies: + +```bash +# Start all services +docker compose up + +# Start specific services +docker compose up postgresql keycloak + +# Run in detached mode +docker compose up -d + +# Stop services +docker compose down +``` + +#### Environment Configuration + +The project uses `.env` files for environment configuration. Copy `.env.example` to `.env` and adjust the values as needed: + +```bash +cp .env.example .env +``` + +Key environment variables include: + +- `DATABASE_URL`: PostgreSQL connection string +- `KEYCLOAK_URL`: Keycloak server URL +- `API_KEY`: For external service authentication +- See `.env.example` for a complete list of required variables + +## Testing Information + +### Backend Testing + +The backend uses JUnit 5 for testing, with custom annotations for different test types: + +- `@UnitTest`: For unit tests +- `@IntegrationTest`: For integration tests + +Tests follow a BDD style with Given/When/Then comments and are organized by domain and layer (application, infrastructure, domain). + +#### Running Backend Tests + +```bash +# Run all tests +./gradlew test + +# Run only unit tests (filter by annotation) +./gradlew test --includes-category "com.lyra.app.test.UnitTest" + +# Run integration tests (requires PostgreSQL & Keycloak) +docker compose up -d postgresql keycloak +./gradlew test --includes-category "com.lyra.app.test.IntegrationTest" +### Running Backend Tests By Type + +```bash +# Run all tests +./gradlew test + +# Run only unit tests (filter by test class name) +./gradlew test --tests "*UnitTest" + +# Alternative: Run unit tests using JUnit tags +./gradlew test -DincludeTags=unit + +# Run integration tests (requires PostgreSQL & Keycloak) +docker compose up -d postgresql keycloak +./gradlew test --tests "*IntegrationTest" + +# Alternative: Run integration tests using JUnit tags +./gradlew test -DincludeTags=integration +# Run specific test +./gradlew test --tests "com.lyra.app.healthcheck.HealthcheckUtilTest" +``` + +#### Writing Backend Tests + +1. Create a test class in the appropriate package under `src/test/kotlin` +2. Annotate the class with `@UnitTest` or `@IntegrationTest` +3. Write test methods with descriptive names using backticks +4. Follow the Given/When/Then pattern + +Example: + +```kotlin +@UnitTest +class HealthcheckUtilTest { + + @Test + fun `should return true when system is healthy`() { + // Given + val healthcheckUtil = HealthcheckUtil() + + // When + val result = healthcheckUtil.isHealthy() + + // Then + Assertions.assertTrue(result) + } +} +``` + +### Frontend Testing + +Frontend tests are written using the Vitest JavaScript testing framework and are located in the `apps/frontend` directory. + +#### Running Frontend Tests + +```bash +# Run all frontend tests +pnpm test + +# Run tests with watch mode +pnpm test:watch +``` + +#### Writing Frontend Tests + +Frontend tests follow a similar BDD style with describe/it blocks: + +```typescript +describe('StringValueObject', () => { + it('should create a StringValueObject with a valid value', () => { + const valueObject = TestValueObject.create('test'); + expect(valueObject.value).toBe('test'); + }); +}); +``` + +## Code Style and Development Practices + +### Code Style + +The project uses EditorConfig for consistent code style across different editors. The main settings are: + +- UTF-8 encoding +- LF line endings +- 2-space indentation for most files +- 4-space indentation for Kotlin, Java, and some other file types + +### Architecture + +The project follows a clean architecture pattern with: + +- Domain layer: Core business logic and entities +- Application layer: Use cases and application services +- Infrastructure layer: External interfaces and implementations + +### Backend Development + +- The backend is built with Kotlin and Spring Boot +- Uses reactive programming with Spring WebFlux +- Follows CQRS pattern with command and query handlers +- Uses event-driven architecture with event publishers + +### Frontend Development + +- The frontend consists of multiple applications: + - Lyra App (Nuxt.js) + - Lyra Landing Page (Astro) +- Uses TypeScript for type safety +- Follows domain-driven design principles + +### Database + +- PostgreSQL is used as the primary database +- Keycloak is used for authentication and authorization + +### Containerization + +- Docker is used for containerization +- Docker Compose is used for local development +- Multiple Dockerfiles for different environments (development, production) + +## Debugging and Troubleshooting + +### Logs + +- Backend logs are available in the console and can be configured in `application.yml` +- Docker logs can be viewed with `docker compose logs` + +### Common Issues + +- If you encounter database connection issues, ensure PostgreSQL is running and accessible +- For Keycloak issues, check the Keycloak logs and ensure it's properly configured + +## Continuous Integration + +The project uses GitHub Actions for CI/CD, with workflows defined in the `.github` directory. diff --git a/README.md b/README.md index 3f1b4c05..55db52e6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@
- +

Lyra

@@ -55,6 +55,14 @@ - [**Tailwindcss**](https://tailwindcss.com/) - A utility-first CSS framework for rapidly building custom designs. - [**tailwindcss-animated**](https://github.com/new-data-services/tailwindcss-animated) - Extended animation utilities for Tailwind CSS. - [**fontsource**](https://fontsource.org/) - Self-host Open Source fonts in neatly bundled NPM packages. +- [**Spring Boot**](https://spring.io/projects/spring-boot) - The web framework for the backend. +- [**Kotlin**](https://kotlinlang.org/) - A modern programming language that makes developers happier. +- [**Gradle**](https://gradle.org/) - A powerful build tool for Java and other languages. +- [**PostgreSQL**](https://www.postgresql.org/) - The world's most advanced open source relational database. +- [**Keycloak**](https://www.keycloak.org/) - Open Source Identity and Access Management for modern applications and services. +- [**Docker**](https://www.docker.com/) - A platform for developing, shipping, and running applications in containers. +- [**Docker Compose**](https://docs.docker.com/compose/) - A tool for defining and running multi-container Docker applications. + # Astro Starter Kit: Basics @@ -116,4 +124,4 @@ Feel free to check [our documentation](https://docs.astro.build) or jump into ou ![Alt](https://repobeats.axiom.co/api/embed/fcbf097295ea4254db6b733582ac982db8fa4fe6.svg "Repobeats analytics image") -![Alt](https://repobeats.axiom.co/api/embed/fcbf097295ea4254db6b733582ac982db8fa4fe6.svg "Repobeats analytics image") +[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/dallay/lyra) diff --git a/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt b/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt index 724aae74..f6d5cb3e 100644 --- a/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt +++ b/apps/backend/src/test/kotlin/com/lyra/app/linkpreview/infrastructure/http/LinkPreviewControllerIntegrationTest.kt @@ -30,7 +30,7 @@ internal class LinkPreviewControllerIntegrationTest : ControllerIntegrationTest( "Typescript, Node.js, Java/Kotlin and Spring Boot.", result?.description, ) - assertEquals("/uploads/me.webp", result?.imageUrl) + assertEquals("/images/me.webp", result?.imageUrl) assertEquals("https://yunielacosta.com/", result?.url) } } diff --git a/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt b/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt index a77d4732..8ce12619 100644 --- a/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt +++ b/build-logic/analysis-convention/src/main/kotlin/com/lyra/buildlogic/analysis/AppOwaspPlugin.kt @@ -2,18 +2,52 @@ package com.lyra.buildlogic.analysis import com.lyra.buildlogic.common.ConventionPlugin import org.gradle.api.Project +import org.gradle.api.tasks.Delete import org.gradle.kotlin.dsl.apply import org.gradle.kotlin.dsl.configure +import org.gradle.kotlin.dsl.register import org.owasp.dependencycheck.gradle.extension.DependencyCheckExtension import org.owasp.dependencycheck.reporting.ReportGenerator +import java.io.File // see https://owasp.org/www-project-dependency-check/#what-is-a-cvss-score private const val FAIL_BUILS_ON_CVSS: Float = 11F // SET THIS TO A REASONABLE VALUE FOR YOUR PROJECT +private const val AUTO_UPDATE: Boolean = true // Enable auto-update of the NVD database +private const val PURGE_DATABASE: Boolean = true // Enable purging of the database to fix corruption issues internal class AppOwaspPlugin : ConventionPlugin { override fun Project.configure() { apply(plugin = "org.owasp.dependencycheck") + // Register a task to purge the dependency check database + tasks.register("purgeDependencyCheckDatabase") { + description = "Purges the dependency check database to fix corruption issues" + group = "security" + + doFirst { + println("Purging dependency check database...") + } + + // Delete the database files in the dependency-check-data directory + delete(fileTree(layout.buildDirectory.dir("dependency-check-data").get().asFile) { + include("*.h2.db") + include("*.mv.db") // Include odc.mv.db file + include("*.trace.db") + include("*.lock.db") + }) + + doLast { + println("Dependency check database purged successfully.") + } + } + + // Make dependencyCheckAnalyze task depend on purgeDependencyCheckDatabase if purging is enabled + if (PURGE_DATABASE) { + tasks.named("dependencyCheckAnalyze").configure { + dependsOn("purgeDependencyCheckDatabase") + } + } + with(extensions) { configure { FAIL_BUILS_ON_CVSS.also { failBuildOnCVSS = it } @@ -31,6 +65,9 @@ internal class AppOwaspPlugin : ConventionPlugin { data.directory = layout.buildDirectory.dir("dependency-check-data").get().asFile.absolutePath + // Enable auto-update of the NVD database + autoUpdate = AUTO_UPDATE + // remove plugin dependencies, for configs see // https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_plugin_and_dependency_management val validConfigurations = listOf("compileClasspath", "runtimeClasspath", "default") diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 8b517423..e34c940d 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ springdoc = "2.6.0" junit = "5.11.2" klint-plugin = "12.1.1" detekt = "1.23.7" -owasp = "10.0.3" +owasp = "12.1.1" asciidoctor = "4.0.2" dokka = "1.9.20" frontend-gradle-plugin = "8.0.0"