Skip to content

Conversation

@MichaelMraka
Copy link
Collaborator

@MichaelMraka MichaelMraka commented Jan 12, 2026

Secure Coding Practices Checklist GitHub Link

Secure Coding Checklist

  • Input Validation
  • Output Encoding
  • Authentication and Password Management
  • Session Management
  • Access Control
  • Cryptographic Practices
  • Error Handling and Logging
  • Data Protection
  • Communication Security
  • System Configuration
  • Database Security
  • File Management
  • Memory Management
  • General Coding Practices

Summary by Sourcery

Add support for publishing inventory views Kafka events from the evaluator, including associated configuration, topic setup, and data model utilities.

New Features:

  • Introduce inventory views event structures and helpers to build host data from system records and templates.
  • Add evaluator logic to generate and publish inventory views events to a configurable Kafka topic with headers.

Enhancements:

  • Refactor template modeling by extracting a reusable TemplateBase shared between templates and inventory views helpers.
  • Extend Kafka messaging utilities to support headers and optional Kafka address overrides from the environment.
  • Update test fixtures and evaluator tests to cover inventory views events and org ID propagation.

Build:

  • Provision the platform.inventory.host-apps Kafka topic and wire its name through Clowder parameters and local/dev Kafka setup scripts.

Deployment:

  • Configure evaluator deployments to receive the inventory views topic via environment variables.

Tests:

  • Add database-backed tests for inventory views event construction, including systems with and without templates.

@jira-linking
Copy link

jira-linking bot commented Jan 12, 2026

Referenced Jiras:
https://issues.redhat.com/browse/RHINENG-22325

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 12, 2026

Reviewer's Guide

Adds inventory views Kafka event publishing from the evaluator, introduces a shared TemplateBase model, and extends the internal Kafka messaging abstraction to support headers and a new inventory views topic across configuration and deployment artifacts.

Sequence diagram for publishing inventory views events from evaluator

sequenceDiagram
    participant Eval as evaluator
    participant InvViews as inventory_views
    participant Mq as mqueue
    participant Kafka as kafka_topic_platform_inventory_host_apps
    participant DB as db

    Eval->>Eval: evaluateAndStore(system, event)
    alt inventory_views_enabled
        Eval->>Eval: publishInventoryViewsEvent(tx, [system], event)
        Eval->>InvViews: MakeInventoryViewsEvent(tx, orgID, systems)
        InvViews->>InvViews: FindSystemsTemplates(tx, systems)
        InvViews->>DB: query TemplateBase by rh_account_id and id
        DB-->>InvViews: templates map
        InvViews->>InvViews: MakeInventoryViewsHosts(systems, templates)
        InvViews-->>Eval: InventoryViewsEvent

        Eval->>Mq: MessageFromJSON(orgID, InventoryViewsEvent, headers)
        Mq-->>Eval: KafkaMessage(key, value, headers)

        Eval->>Mq: inventoryViewsPublisher.WriteMessages(ctx, KafkaMessage)
        Mq->>Kafka: send message with key, value, headers
        Kafka-->>Mq: ack
        Mq-->>Eval: nil error
    else publisher_not_configured
        Eval-->>Eval: publishInventoryViewsEvent returns without sending
    end
Loading

ER diagram for template and template_base usage in inventory views

erDiagram
    template_base {
        int64 id PK
        int rh_account_id PK
        string uuid
        string name
    }

    template {
        int64 id PK
        int rh_account_id PK
        string uuid
        string name
        string environment_id
        string arch
        string version
        time created_at
        time updated_at
        time last_edited
    }

    system_platform {
        int64 id PK
        int rh_account_id
        string inventory_id
        int64 template_id FK
    }

    template_base ||--o{ template : is_embedded_in
    template_base ||--o{ system_platform : referenced_by
    template ||--|| template_base : shares_primary_key
Loading

Updated class diagram for templates, inventory views, and Kafka messaging

classDiagram
    class TemplateBase {
        +int64 ID
        +int RhAccountID
        +string UUID
        +string Name
        +TableName() string
    }

    class Template {
        +string EnvironmentID
        +string Arch
        +string Version
        +time.Time CreatedAt
        +time.Time UpdatedAt
        +time.Time LastEdited
        +TableName() string
    }

    TemplateBase <|-- Template

    class SystemPlatform {
        +int64 ID
        +int RhAccountID
        +string InventoryID
        +*int64 TemplateID
        +int ApplicableAdvisorySecCountCache
        +int ApplicableAdvisoryBugCountCache
        +int ApplicableAdvisoryEnhCountCache
        +int ApplicableAdvisoryCountCache
        +int InstallableAdvisorySecCountCache
        +int InstallableAdvisoryBugCountCache
        +int InstallableAdvisoryEnhCountCache
        +int InstallableAdvisoryCountCache
        +int PackagesInstalled
        +int PackagesInstallable
        +int PackagesApplicable
    }

    TemplateBase <.. SystemPlatform : used_for_template_lookup

    class InventoryViewsHostData {
        +int ApplicableRhsaCount
        +int ApplicableRhbaCount
        +int ApplicableRheaCount
        +int ApplicableOtherCount
        +int InstallableRhsaCount
        +int InstallableRhbaCount
        +int InstallableRheaCount
        +int InstallableOtherCount
        +int PackagesInstalled
        +int PackagesInstallable
        +int PackagesApplicable
        +*string TemplateName
        +*string TemplateUUID
    }

    class InventoryViewsHost {
        +string ID
        +InventoryViewsHostData Data
    }

    class InventoryViewsEvent {
        +string OrgID
        +string Timestamp
        +[]InventoryViewsHost Hosts
        +MakeInventoryViewsEvent(tx *gorm.DB, orgID string, systems []SystemPlatform) (InventoryViewsEvent, error)
        +MakeInventoryViewsHosts(systems []SystemPlatform, templates map[int64]TemplateBase) ([]InventoryViewsHost, error)
        +FindSystemsTemplates(tx *gorm.DB, systems []SystemPlatform) (map[int64]TemplateBase, error)
    }

    InventoryViewsHostData <.. InventoryViewsHost : contains
    InventoryViewsHost <.. InventoryViewsEvent : aggregates

    class KafkaMessage {
        +[]byte Key
        +[]byte Value
        +[]kafka.Header Headers
    }

    class mqueue {
        +MessageFromJSON(key string, value interface, headers []kafka.Header) (KafkaMessage, error)
        +Writer
    }

    class kafkaGoReaderImpl {
        -*kafka.Reader Reader
        +HandleMessages(handler MessageHandler)
    }

    class kafkaGoWriterImpl {
        -*kafka.Writer Writer
        +WriteMessages(ctx context.Context, msgs ...KafkaMessage) error
    }

    KafkaMessage <.. mqueue : created_by
    KafkaMessage <.. kafkaGoWriterImpl : converted_to_kafka_Message
    KafkaMessage <.. kafkaGoReaderImpl : constructed_from_kafka_Message

    class Evaluator {
        -bool enableInventoryViews
        +configureInventoryViews()
        +publishInventoryViewsEvent(tx *gorm.DB, systems []SystemPlatform, origin *mqueue.PlatformEvent) error
    }

    class CoreCfg {
        +string InventoryViewsTopic
        +string KafkaAddress
        +[]string KafkaServers
    }

    Evaluator ..> InventoryViewsEvent : publishes
    Evaluator ..> KafkaMessage : sends
    Evaluator ..> CoreCfg : reads_configuration
    CoreCfg ..> mqueue : new_kafka_writer
    kafkaGoWriterImpl ..|> mqueue.Writer
    kafkaGoReaderImpl ..|> mqueue.Reader
Loading

File-Level Changes

Change Details Files
Introduce inventory views event construction and publishing from evaluator to a dedicated Kafka topic with org-scoped host data.
  • Add inventory views feature flag and configuration wiring in evaluator, including topic-based publisher initialization.
  • Implement inventory views event builder that aggregates per-host advisory/package counts and template metadata, including DB lookups for templates.
  • Publish inventory views events after successful evaluation using the internal message queue, with appropriate headers, logging, metrics, and tests for event generation.
evaluator/evaluate.go
evaluator/inventory_views.go
base/inventory_views/inventory_views.go
base/inventory_views/inventory_views_test.go
evaluator/evaluate_test.go
deploy/clowdapp.yaml
base/utils/config.go
dev/kafka/setup.sh
Refactor template model to share base fields between DB queries and listeners and adjust test helpers accordingly.
  • Extract TemplateBase from Template to contain primary key and identity fields and set its table mapping.
  • Update Template usages in listener and database test helpers to embed TemplateBase and populate shared fields correctly.
base/models/models.go
listener/templates.go
base/database/testing.go
base/inventory_views/inventory_views.go
Extend Kafka messaging abstraction to carry headers and allow configuring Kafka via a single KAFKA_ADDRESS variable.
  • Add Headers to KafkaMessage and propagate them through kafka-go reader/writer implementation.
  • Extend MessageFromJSON to accept and set Kafka headers and update all callers to pass headers (or nil).
  • Support overriding KafkaAddress and KafkaServers via KAFKA_ADDRESS env variable and expose INVENTORY_VIEWS_TOPIC in core config, env, and clowder translation/printing.
  • Register the new inventory views topic in local/dev Kafka setup and clowdapp kafkaTopics plus parameterize INVENTORY_VIEWS_TOPIC.
base/mqueue/mqueue.go
base/mqueue/message.go
base/mqueue/mqueue_impl_gokafka.go
evaluator/notifications.go
evaluator/notifications_test.go
evaluator/remediations.go
base/utils/config.go
dev/kafka/setup.sh
deploy/clowdapp.yaml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@codecov-commenter
Copy link

codecov-commenter commented Jan 12, 2026

Codecov Report

❌ Patch coverage is 73.50427% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 59.18%. Comparing base (506bc9a) to head (f5dd08b).

Files with missing lines Patch % Lines
evaluator/inventory_views.go 73.33% 4 Missing and 4 partials ⚠️
base/database/testing.go 0.00% 6 Missing ⚠️
base/inventory_views/inventory_views.go 88.88% 3 Missing and 3 partials ⚠️
base/utils/config.go 42.85% 3 Missing and 1 partial ⚠️
evaluator/evaluate.go 50.00% 3 Missing and 1 partial ⚠️
base/mqueue/message.go 0.00% 2 Missing ⚠️
base/models/models.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #2014      +/-   ##
==========================================
+ Coverage   59.01%   59.18%   +0.16%     
==========================================
  Files         131      133       +2     
  Lines        8493     8599     +106     
==========================================
+ Hits         5012     5089      +77     
- Misses       2947     2967      +20     
- Partials      534      543       +9     
Flag Coverage Δ
unittests 59.18% <73.50%> (+0.16%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@MichaelMraka MichaelMraka force-pushed the pr1 branch 3 times, most recently from b4121ec to 158785f Compare January 13, 2026 10:22
@MichaelMraka MichaelMraka marked this pull request as ready for review January 13, 2026 12:46
@MichaelMraka MichaelMraka requested a review from TenSt January 13, 2026 12:46
Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • In MakeInventoryViewsHosts, when a system has a TemplateID that isn't present in the templates map, you log a warning but still unconditionally set TemplateName/TemplateUUID from the zero-value template variable; this yields non-nil empty strings instead of nil, which contradicts the test expectations and should be guarded by the ok flag.
  • MakeInventoryViewsHosts returns ([]InventoryViewsHost, error) but never actually produces a non-nil error; consider simplifying the signature to drop the error return or add concrete error conditions to make the return type meaningful.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In `MakeInventoryViewsHosts`, when a system has a `TemplateID` that isn't present in the `templates` map, you log a warning but still unconditionally set `TemplateName`/`TemplateUUID` from the zero-value `template` variable; this yields non-nil empty strings instead of `nil`, which contradicts the test expectations and should be guarded by the `ok` flag.
- `MakeInventoryViewsHosts` returns `([]InventoryViewsHost, error)` but never actually produces a non-nil error; consider simplifying the signature to drop the `error` return or add concrete error conditions to make the return type meaningful.

## Individual Comments

### Comment 1
<location> `base/inventory_views/inventory_views_test.go:68-77` </location>
<code_context>
+func TestMakeInventoryViewsEventNoTemplate(t *testing.T) {
</code_context>

<issue_to_address>
**suggestion (testing):** Consider adding a test for systems that reference a non-existent template row

Current tests cover valid templates, an empty systems slice, and `TemplateID == nil`. There’s still an untested path where `TemplateID != nil` but `FindSystemsTemplates` returns no row (e.g. deleted template): we log a warning, but the resulting `TemplateName`/`TemplateUUID` behavior isn’t asserted. Please add a DB-backed test that sets `TemplateID` to a non-existent template ID and verifies that `MakeInventoryViewsEvent` does not error, and that `TemplateName`/`TemplateUUID` match the intended behavior for dangling template references.

Suggested implementation:

```golang
func TestMakeInventoryViewsEventNoTemplate(t *testing.T) {
	utils.SkipWithoutDB(t)
	core.SetupTestEnvironment()

	tx := database.DB.Begin()
	defer tx.Rollback()

	var rhAccount models.RhAccount
	assert.NoError(t, tx.Where("id = ?", rhAccountID).First(&rhAccount).Error)
	assert.NotEmpty(t, *rhAccount.OrgID)
	orgID := *rhAccount.OrgID

	// Use a template ID that does not exist in the templates table to simulate
	// a dangling template reference (e.g. the template was deleted).
	var nonExistentTemplateID uint = 999999999

	system := models.SystemPlatform{
		RhAccountID: &rhAccount.ID,
		OrgID:       &orgID,
		TemplateID:  &nonExistentTemplateID,
	}

	event, err := MakeInventoryViewsEvent(tx, orgID, []models.SystemPlatform{system})
	assert.NoError(t, err)
	assert.Equal(t, orgID, event.OrgID)
	assert.Len(t, event.Hosts, 1)

	host := event.Hosts[0]

	// When a system references a non-existent template row, we only log a warning
	// and still emit the host; template-related fields should reflect the
	// "missing template" behavior (no template data attached).
	assert.Zero(t, host.TemplateUUID)
	assert.Zero(t, host.TemplateName)
}

```

1. Ensure that `models.SystemPlatform` has the fields `RhAccountID`, `OrgID`, and `TemplateID` with compatible types:
   - `RhAccountID` should match the type of `rhAccount.ID` (commonly `uint` or `int64`) and be a pointer if used as `&rhAccount.ID`.
   - `OrgID` should be a `*string` to match `orgID := *rhAccount.OrgID`.
   - `TemplateID` should be a pointer to an integer type (here `*uint`). If it is a different type (e.g. `*int64` or `*uuid.UUID`), adjust the definition of `nonExistentTemplateID` and the field type accordingly.
2. Confirm the `event.Hosts` element type exposes `TemplateUUID` and `TemplateName` fields. If their names or types differ:
   - Update `host.TemplateUUID` / `host.TemplateName` to the correct field names.
   - Keep the `assert.Zero` checks so the test remains agnostic to whether the fields are strings or pointers; `assert.Zero` will pass for `""` or `nil`.
3. If `MakeInventoryViewsEvent` is expected to behave differently for dangling template references (e.g. keep a UUID but clear only the name), adjust the assertions on `host.TemplateUUID` / `host.TemplateName` to match that intended behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

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