Skip to content

add Gateway teaser page for CE users - #1593

Open
nicolachr wants to merge 11 commits into
developfrom
gateway/add-ce-teaser
Open

add Gateway teaser page for CE users#1593
nicolachr wants to merge 11 commits into
developfrom
gateway/add-ce-teaser

Conversation

@nicolachr

@nicolachr nicolachr commented May 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a static Gateway teaser page for CE users, accessible under Tools > Gateway in the navbar. The page shows:

  • The user's real CE project with live data: issue/evidence/node counts, top 3 vulnerabilities (progress bars coloured by tag), and top 3 affected nodes (progress bars coloured by tag)
  • A mock projects table showing the CE project alongside three example projects with Gateway-style team/theme metadata

This follows the "show don't gate" pattern used for Issue Library and Remediation Tracker — CE users see a real, functional preview of the feature rather than a locked-out placeholder.

How to test

  1. Start the dev server (bin/dev) and log in as any user
  2. Open the Tools menu in the navbar — verify Gateway appears alphabetically before Issue Library
  3. Click Gateway — verify the page loads at /projects/1/addons/gateway
  4. Active project card:
    • Project name, issue/evidence/node counts reflect the real CE project (project ID 1)
    • "Last updated" shows a relative time if any activity exists
    • Top 3 Vulnerabilities bars are coloured by the issue's first tag (grey if no evidence or no tag)
    • Top 3 Affected Nodes bars are coloured by tag; nodes with no issues show the empty state
  5. Empty states: remove all issues or evidence from the project and verify the empty state renders for each section
  6. Projects table: verify the real CE project appears first (team: Galactica, theme: Athena), followed by three mock projects
  7. Verify all project name links in the table and the active card trigger the js-try-pro upsell modal (not a navigation)
  8. Pro: confirm the Gateway route and navbar link are absent when Dradis::Pro is defined

Other Information

  • StaticPagesHelper ports chart_styles, top_issues_by_evidence_count, top_nodes_by_issue_count, and issues_grouped_by_tag from the gateway engine's active-projects/hide-empty-content branch

I assign all rights, including copyright, to any future Dradis work by myself to Security Roots.

Check List

  • Added a CHANGELOG entry
  • Commit message has a detailed description of what changed and why.

@etdsoft etdsoft left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This PR adds a Gateway teaser page for CE users following the established "show don't gate" pattern. The implementation is clean overall, but there's a crash path from an unguarded Project.find(1), a global .card-title margin override that causes visual regression risk across the app, an unscoped Activity query, and missing tests for the new helper methods.

Findings

F1 [High|sad-path] app/controllers/static_pages_controller.rb:23 — Project.find(1) crashes if project 1 does not exist

What: set_gateway_projects calls Project.find(1), which raises ActiveRecord::RecordNotFound (500 error) if no project with ID 1 exists. This is the first static teaser page that performs a real database lookup — Issue Library and Remediation Tracker use only mock data.

Why: While CE conventionally has a single project with ID 1, this isn't guaranteed after a DB reset, re-seed with different auto-increment, or if the default project was deleted. The page becomes the only "show don't gate" page that can 500 while the others render fine.

How to fix: Use Project.first instead of Project.find(1) — it's more resilient and semantically correct (CE has one project, use it). Add a guard for the nil case:

def set_gateway_projects
  @project = Project.first
  return redirect_to root_path unless @project

  @projects = [
    { name: @project.name, ... }
  ] + gateway_projects
end

F2 [Medium|correctness] app/assets/stylesheets/hera/modules.scss:118 — global .card-title margin override causes app-wide regression risk

What: The new rule .card .card-title { margin-bottom: 0; } removes bottom margin from every .card-title inside a .card in the entire application — affecting comments, boards, subscriptions, issues empty-state actions, and more.

Why: This is broader than needed. The existing issuelib teaser already solved this locally with <h4 class="card-title mb-0"> (a Bootstrap utility class on the element). The global override silently changes spacing on ~10 unrelated views and makes the issuelib's mb-0 class redundant. Card titles in comments, boards, and subscriptions may now render with incorrect spacing.

How to fix: Remove the .card-title block from modules.scss and add mb-0 to the gateway card title, matching the issuelib pattern:

<h4 class="card-title mb-0">Projects</h4>

F3 [Medium|correctness] app/controllers/static_pages_controller.rb:30 — unscoped Activity.maximum(:created_at) queries all projects

What: set_gateway_projects uses Activity.maximum(:created_at) to populate the updated_at field for the projects table row. This queries the entire activities table, not scoped to project 1. Meanwhile, the active project card in the view correctly uses @project.activities.maximum(:created_at).

Why: If multiple projects exist in CE (created via upload or setup), the table row will show a "last updated" date from a different project's activity, while the card above it shows the correct project-scoped date. The same project could display two different "last updated" values on the same page.

How to fix: Scope the query to the project:

updated_at: @project.activities.maximum(:created_at) || Date.today

F4 [Medium|tests] app/helpers/static_pages_helper.rb:0 — no tests for helper methods with non-trivial query logic

What: StaticPagesHelper introduces four methods — chart_styles, issues_grouped_by_tag, top_issues_by_evidence_count, and top_nodes_by_issue_count — with LEFT JOIN, GROUP BY, custom Arel.sql ordering, and conditional logic. None have tests. The gateway_index controller action and request spec are also absent.

Why: These methods contain real database query logic (joins, grouping, aggregation) and branching (nil tag handling, zero-evidence fallback). Unlike the hardcoded mock data in tickets and issuelib_entries, these run live queries against project data. A future schema change or association rename could silently break them. The PR description notes these were ported from the gateway engine where they were "tested and peer-reviewed" — but those tests don't exist in CE.

How to fix: Add specs covering the helper methods and the gateway_index route. At minimum: top_issues_by_evidence_count orders by evidence count and handles zero evidence; top_nodes_by_issue_count orders by distinct issue count and excludes non-user nodes; issues_grouped_by_tag groups by first tag sorted by position and places untagged last; gateway_index renders successfully and handles empty projects.

F5 [Low|consistency] app/assets/stylesheets/hera/modules/_active_project.scss:2 — dead CSS for .avatars and .donuts sections

What: The stylesheet includes ~100 lines of styles for .avatars (lines 2–34) and .donuts (lines 45–106) that are never used in any CE view. The PR description states these sections were "omitted as they have no CE equivalent," but the latest commit (sync _active_project.scss with Pro for CE-Pro parity) brought them back.

Why: Dead CSS increases bundle size and maintenance surface. The .more-gravatars rule also has a duplicate border-radius: 50% declaration (lines 25 and 27), suggesting a copy-paste from Pro without cleanup.

How to fix: Either remove .avatars and .donuts blocks from the CE version (matching the original intent), or update the PR description to explain why syncing the full Pro stylesheet is preferred. If keeping them, remove the duplicate border-radius on line 27.

F6 [Low|consistency] app/views/static_pages/gateway_index.html.erb:38 — raw HTML anchor tag instead of link_to

What: <a href="https://dradis.com/tools/gateway.html" target="_blank">Dradis Gateway</a> uses a raw HTML tag.

Why: CLAUDE.md convention: "Always use Rails helpers — never raw HTML tags for assets or links."

How to fix: <%= link_to 'Dradis Gateway', 'https://dradis.com/tools/gateway.html', target: '_blank' %>

F7 [Low|hygiene] CHANGELOG:5 — changelog entry missing future-tense verb

What: The changelog entry is just Gateway under the Show don't gate section, with no verb describing what the upgrade does.

Why: CLAUDE.md changelog rules: "Feature entries: description starts with a future tense verb — frame it as 'What will this upgrade do to my instance?'" The existing Node-level Methodologies entry has the same issue, but extending a pattern that doesn't match the documented convention is worth flagging.

How to fix: Change to something like:

  - Show don't gate:
    - Gateway: add teaser page with live project data
    - Node-level Methodologies

Notes

  • The Arel.sql(...) calls in StaticPagesHelper use static strings only (no interpolation), so they're safe from SQL injection.
  • The hardcoded Project.find(1) and projects/1/addons/gateway route follow the exact same pattern as the existing issuelib and remediation tracker teasers. The find(1) pattern itself is the concern, not the route design.
  • The js-try-pro class is used as a JS hook throughout the CE codebase (~20 occurrences). While CLAUDE.md conventions prefer data-behavior selectors, this is a deeply established pattern — refactoring it is a separate task.

@nicolachr
nicolachr force-pushed the gateway/add-ce-teaser branch from 3a7c56c to aef9151 Compare June 30, 2026 07:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants