Skip to content

Conversation

@sharadcrest
Copy link
Contributor

Proposed commit message

The initial release includes event data stream, associated dashboard
and visualizations.

forescout fields are mapped to their corresponding ECS fields where possible.

Test samples were derived from live data samples, which were subsequently
sanitized.

Checklist

  • I have reviewed tips for building integrations and this pull request is aligned with them.
  • I have verified that all data streams collect metrics or logs.
  • I have added an entry to my package's changelog.yml file.
  • I have verified that Kibana version constraints are current according to guidelines.
  • I have verified that any added dashboard complies with Kibana's Dashboard good practices

How to test this PR locally

To test the forescout package:

  • Clone integrations repo.
  • Install elastic package locally.
  • Start elastic stack using elastic-package.
  • Move to integrations/packages/forescout directory.
  • Run the following command to run tests.

elastic-package test

Run asset tests for the package
2025/12/09 15:08:54  INFO License text found in "/home/devuser/github/integrations/LICENSE.txt" will be included in package
--- Test results for package: forescout - START ---
╭───────────┬─────────────┬───────────┬────────────────────────────────────────────────────────────────────┬────────┬──────────────╮
│ PACKAGE   │ DATA STREAM │ TEST TYPE │ TEST NAME                                                          │ RESULT │ TIME ELAPSED │
├───────────┼─────────────┼───────────┼────────────────────────────────────────────────────────────────────┼────────┼──────────────┤
│ forescout │             │ asset     │ dashboard forescout-52ac29ab-2ce2-4d68-937d-cac1cb92ab47 is loaded │ PASS   │        921ns │
│ forescout │             │ asset     │ search forescout-09d5d60b-1995-4851-b518-9337a4761cae is loaded    │ PASS   │        136ns │
│ forescout │ event       │ asset     │ index_template logs-forescout.event is loaded                      │ PASS   │        261ns │
│ forescout │ event       │ asset     │ ingest_pipeline logs-forescout.event-0.1.0 is loaded               │ PASS   │        203ns │
╰───────────┴─────────────┴───────────┴────────────────────────────────────────────────────────────────────┴────────┴──────────────╯
--- Test results for package: forescout - END   ---
Done
Run pipeline tests for the package
--- Test results for package: forescout - START ---
╭───────────┬─────────────┬───────────┬────────────────────────────────────────────────────┬────────┬──────────────╮
│ PACKAGE   │ DATA STREAM │ TEST TYPE │ TEST NAME                                          │ RESULT │ TIME ELAPSED │
├───────────┼─────────────┼───────────┼────────────────────────────────────────────────────┼────────┼──────────────┤
│ forescout │ event       │ pipeline  │ (ingest pipeline warnings test-pipeline-event.log) │ PASS   │ 353.515412ms │
│ forescout │ event       │ pipeline  │ test-pipeline-event.log                            │ PASS   │ 183.035682ms │
╰───────────┴─────────────┴───────────┴────────────────────────────────────────────────────┴────────┴──────────────╯
--- Test results for package: forescout - END   ---
Done
Run policy tests for the package
--- Test results for package: forescout - START ---
No test results
--- Test results for package: forescout - END   ---
Done
Run script tests for the package
--- Test results for package: forescout - START ---
PKG forescout
[no test files]
--- Test results for package: forescout - END ---
Done
Run static tests for the package
--- Test results for package: forescout - START ---
╭───────────┬─────────────┬───────────┬──────────────────────────┬────────┬──────────────╮
│ PACKAGE   │ DATA STREAM │ TEST TYPE │ TEST NAME                │ RESULT │ TIME ELAPSED │
├───────────┼─────────────┼───────────┼──────────────────────────┼────────┼──────────────┤
│ forescout │ event       │ static    │ Verify sample_event.json │ PASS   │ 125.779254ms │
╰───────────┴─────────────┴───────────┴──────────────────────────┴────────┴──────────────╯
--- Test results for package: forescout - END   ---
Done
Run system tests for the package
2025/12/09 15:08:59  INFO Installing package...
2025/12/09 15:08:59  INFO License text found in "/home/devuser/github/integrations/LICENSE.txt" will be included in package
2025/12/09 15:09:11  INFO Running test for data_stream "event" with configuration 'udp'
2025/12/09 15:09:20  INFO Setting up independent Elastic Agent...
2025/12/09 15:09:31  INFO Setting up service...
2025/12/09 15:09:53  INFO Validating test case...
2025/12/09 15:09:54  INFO Tearing down service...
2025/12/09 15:09:55  INFO Write container logs to file: /home/devuser/github/integrations/build/container-logs/forescout-event-udp-1765273195104041584.log
2025/12/09 15:09:58  INFO Tearing down agent...
2025/12/09 15:09:58  INFO Write container logs to file: /home/devuser/github/integrations/build/container-logs/elastic-agent-1765273198432716438.log
2025/12/09 15:10:11  INFO Running test for data_stream "event" with configuration 'tcp'
2025/12/09 15:10:20  INFO Setting up independent Elastic Agent...
2025/12/09 15:10:31  INFO Setting up service...
2025/12/09 15:10:51  INFO Validating test case...
2025/12/09 15:10:52  INFO Tearing down service...
2025/12/09 15:10:53  INFO Write container logs to file: /home/devuser/github/integrations/build/container-logs/forescout-event-tcp-1765273253274622964.log
2025/12/09 15:10:56  INFO Tearing down agent...
2025/12/09 15:10:56  INFO Write container logs to file: /home/devuser/github/integrations/build/container-logs/elastic-agent-1765273256451904211.log
2025/12/09 15:11:09  INFO Uninstalling package...
--- Test results for package: forescout - START ---
╭───────────┬─────────────┬───────────┬───────────┬────────┬───────────────╮
│ PACKAGE   │ DATA STREAM │ TEST TYPE │ TEST NAME │ RESULT │  TIME ELAPSED │
├───────────┼─────────────┼───────────┼───────────┼────────┼───────────────┤
│ forescout │ event       │ system    │ tcp       │ PASS   │ 41.396462621s │
│ forescout │ event       │ system    │ udp       │ PASS   │ 43.344074374s │
╰───────────┴─────────────┴───────────┴───────────┴────────┴───────────────╯
--- Test results for package: forescout - END   ---
Done

Related issues

Screenshots

image image

Go Code for Ingest Pipeline Generation

The event data stream pipeline is generated using Go code with the help of Dispear library.

package main

import (
	"fmt"
	"strings"

	. "github.com/efd6/dispear"
)

const (
	ECSVersion = "9.2.0"
	PkgRoot    = "json"
)
const errorFormat = "Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} in pipeline {{{_ingest.on_failure_pipeline}}} failed with message: {{{_ingest.on_failure_message}}}"

// safeNavigateAndCheck converts a dot-separated field path to a safe navigation string.
//
// Example:
// "forescout.event.message" -> "ctx.forescout?.event?.message"
func safeNavigateAndCheck(field string) string {
	parts := strings.Split(field, ".")
	condition := "ctx"
	for i, part := range parts {
		if i > 0 { // Skip the first part which is already included in the condition
			condition += fmt.Sprintf("?.%s", part)
		} else {
			condition += fmt.Sprintf(".%s", part)
		}
	}
	return condition
}

func main() {

	// Initial processors of pipeline

	DESCRIPTION("Pipeline for processing event logs.")

	SET("ecs.version").VALUE(ECSVersion).TAG("set ecs.version to 9.2.0")

	// Setting event.* fields
	BLANK()
	BLANK().COMMENT("Set event.* fields")

	SET("event.kind").
		TAG(fmt.Sprintf("set %s to %s", "event.kind", "event")).
		VALUE("event")

	// extract fields from message
	BLANK()
	BLANK().COMMENT("extract fields from message")

	DISSECT("message", "%{forescout.event.service} : TTY=%{forescout.event.tty} ; PWD=%{forescout.event.pwd} ; USER=%{forescout.event.user} ; COMMAND=%{forescout.event.command}").
		IF(safeNavigateAndCheck("message") + " != null").
		DESCRIPTION("Extract fields from the `message` field using the Dissect processor.").
		IGNORE_FAILURE(true)

	// Map custom fields to corresponding ECS and related fields.
	BLANK()
	BLANK().COMMENT("Map custom fields to corresponding ECS and related fields.")

	SET("forescout.event.message").
		TAG(fmt.Sprintf("set %s to %s", "forescout.event.message", "message")).
		COPY_FROM("message").
		IGNORE_EMPTY(true)

	for _, mapping := range []struct {
		field, targetField string
	}{
		{field: "forescout.event.pwd", targetField: "process.working_directory"},
		{field: "forescout.event.user", targetField: "user.name"},
		{field: "forescout.event.user", targetField: "process.user.name"},
		{field: "forescout.event.command", targetField: "process.command_line"},
	} {
		SET(mapping.targetField).
			COPY_FROM(mapping.field).
			TAG(fmt.Sprintf("set %s from %s", mapping.targetField, strings.ReplaceAll(mapping.field, ".", "_"))).
			IGNORE_EMPTY(true)
	}

	// Map related fields
	BLANK()
	BLANK().COMMENT("Append related.* fields")

	APPEND("related.user", "{{{process.user.name}}}").
		ALLOW_DUPLICATES(false).IF(safeNavigateAndCheck("forescout.event.user") + " != null")
	APPEND("related.hosts", "{{{log.syslog.hostname}}}").
		ALLOW_DUPLICATES(false).IF(safeNavigateAndCheck("log.syslog.hostname") + " != null")

	// Remove duplicate custom fields
	BLANK()
	BLANK().COMMENT("Remove duplicate custom fields")
	REMOVE(
		"forescout.event.message",
		"forescout.event.pwd",
		"forescout.event.user",
		"forescout.event.command",
	).
		IF("ctx.tags == null || !ctx.tags.contains('preserve_duplicate_custom_fields')").
		TAG("remove_custom_duplicate_fields").
		IGNORE_MISSING(true)

	// Clean up script

	BLANK()
	BLANK().COMMENT("Cleanup")

	SCRIPT().
		TAG("script_to_drop_null_values").
		DESCRIPTION("This script processor iterates over the whole document to remove fields with null values.").
		LANG("painless").
		SOURCE(`
		void handleMap(Map map) {
			map.values().removeIf(v -> {
				if (v instanceof Map) {
					handleMap(v);
				} else if (v instanceof List) {
					handleList(v);
				}
				return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0)
			});
		}
		void handleList(List list) {
			list.removeIf(v -> {
				if (v instanceof Map) {
					handleMap(v);
				} else if (v instanceof List) {
					handleList(v);
				}
				return v == null || v == '' || (v instanceof Map && v.size() == 0) || (v instanceof List && v.size() == 0)
			});
		}
		handleMap(ctx);
		`)

	// Set and Append processor on last

	SET("event.kind").VALUE("pipeline_error").
		TAG("set event.kind to pipeline_error").
		IF("ctx.error?.message != null")
	APPEND("tags", "preserve_original_event").
		IF("ctx.error?.message != null").
		ALLOW_DUPLICATES(false)

	// Global on failure processor

	ON_FAILURE(
		APPEND("error.message", errorFormat),
		SET("event.kind").VALUE("pipeline_error").
			TAG("set event.kind to pipeline_error"),
		APPEND("tags", "preserve_original_event").
			ALLOW_DUPLICATES(false),
	)

	// Generate the pipeline

	Generate()
}

@andrewkroh andrewkroh added documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:forescout [Integration not found in source] Crest Contributions from Crest developement team. New Integration Issue or pull request for creating a new integration package. dashboard Relates to a Kibana dashboard bug, enhancement, or modification. labels Dec 9, 2025
@sharadcrest sharadcrest marked this pull request as ready for review December 15, 2025 07:08
@sharadcrest sharadcrest requested a review from a team as a code owner December 15, 2025 07:08
@botelastic
Copy link

botelastic bot commented Jan 14, 2026

Hi! We just realized that we haven't looked into this PR in a while. We're sorry! We're labeling this issue as Stale to make it hit our filters and make sure we get back to it as soon as possible. In the meantime, it'd be extremely helpful if you could take a look at it as well and confirm its relevance. A simple comment with a nice emoji will be enough :+1. Thank you for your contribution!

@botelastic botelastic bot added the Stalled label Jan 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Crest Contributions from Crest developement team. dashboard Relates to a Kibana dashboard bug, enhancement, or modification. documentation Improvements or additions to documentation. Applied to PRs that modify *.md files. Integration:forescout [Integration not found in source] New Integration Issue or pull request for creating a new integration package. Stalled

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants