Basic Usage Examples¶
This page provides practical code examples for common operations in asset-db. It demonstrates how to initialize a repository, create entities and edges, add metadata through tags, and perform basic queries. These examples assume you have already installed asset-db (see Installation) and configured your database connection (see Database Configuration).
For detailed information about the repository interface and all available methods, see Repository Interface. For advanced usage patterns including caching, see Caching System.
Initializing a Repository¶
The entry point for using asset-db is the repository.New() factory function, which creates the appropriate repository implementation based on the database type.
Basic Initialization Pattern¶
The initialization process follows a simple factory pattern:
graph LR
App["Application Code"]
Factory["repository.New()"]
SQLRepo["sqlRepository instance"]
NeoRepo["neoRepository instance"]
Repo["repository.Repository interface"]
App -->|"New(dbtype, dsn)"| Factory
Factory -->|"dbtype='postgres'<br/>or 'sqlite'"| SQLRepo
Factory -->|"dbtype='neo4j'"| NeoRepo
SQLRepo -.->|implements| Repo
NeoRepo -.->|implements| Repo
Factory -->|returns| Repo
App -->|uses| Repo
Example: PostgreSQL Repository¶
import (
"github.com/owasp-amass/asset-db/repository"
)
// Initialize PostgreSQL repository
repo, err := repository.New("postgres",
"host=localhost port=5432 user=myuser password=mypass dbname=assetdb")
if err != nil {
// Handle error
}
defer repo.Close()
Example: SQLite Repository¶
// Initialize SQLite file-based repository
repo, err := repository.New("sqlite", "assets.db")
if err != nil {
// Handle error
}
defer repo.Close()
// Or use in-memory SQLite for testing
repo, err := repository.New("sqlite_memory", ":memory:")
Example: Neo4j Repository¶
// Initialize Neo4j repository
repo, err := repository.New("neo4j",
"bolt://localhost:7687")
if err != nil {
// Handle error
}
defer repo.Close()
Working with Entities (Assets)¶
Entities represent nodes in the asset graph. The asset-db system uses the Open Asset Model (OAM) to define standardized asset types.
Entity Lifecycle Operations¶
graph TB
Asset["oam.Asset<br/>(FQDN, IPAddress, etc.)"]
CreateAsset["CreateAsset(asset)"]
Entity["types.Entity<br/>(with ID, timestamps)"]
FindById["FindEntityById(id)"]
FindByContent["FindEntitiesByContent(asset, since)"]
FindByType["FindEntitiesByType(assetType, since)"]
DeleteEntity["DeleteEntity(id)"]
Asset -->|input| CreateAsset
CreateAsset -->|returns| Entity
Entity -->|query by ID| FindById
Entity -->|query by content| FindByContent
Entity -->|query by type| FindByType
Entity -->|remove| DeleteEntity
Example: Creating an FQDN Entity¶
import (
"github.com/owasp-amass/open-asset-model/dns"
)
// Create an FQDN asset
fqdn := &dns.FQDN{Name: "www.example.com"}
// Store it as an entity
entity, err := repo.CreateAsset(fqdn)
if err != nil {
// Handle error
}
// The entity now has an ID and timestamps
fmt.Printf("Entity ID: %s\n", entity.ID)
fmt.Printf("Created At: %s\n", entity.CreatedAt)
fmt.Printf("Last Seen: %s\n", entity.LastSeen)
Example: Creating an IP Address Entity¶
import (
"net/netip"
"github.com/owasp-amass/open-asset-model/network"
)
// Create an IP address asset
ip, _ := netip.ParseAddr("192.168.1.1")
ipAsset := &network.IPAddress{
Address: ip,
Type: "IPv4",
}
entity, err := repo.CreateAsset(ipAsset)
if err != nil {
// Handle error
}
Example: Creating Other Asset Types¶
import (
"net/netip"
"github.com/owasp-amass/open-asset-model/network"
oamreg "github.com/owasp-amass/open-asset-model/registration"
)
// Autonomous System
as := &network.AutonomousSystem{Number: 15169}
asEntity, err := repo.CreateAsset(as)
// Netblock (CIDR)
cidr, _ := netip.ParsePrefix("198.51.100.0/24")
netblock := &network.Netblock{
CIDR: cidr,
Type: "IPv4",
}
netblockEntity, err := repo.CreateAsset(netblock)
// Registration Record
autnumRecord := &oamreg.AutnumRecord{
Number: 15169,
Handle: "AS15169",
Name: "GOOGLE",
}
recordEntity, err := repo.CreateAsset(autnumRecord)
Duplicate Asset Handling¶
When you create an asset that already exists (same content), the system updates the LastSeen timestamp rather than creating a duplicate.
// Create asset first time
entity1, _ := repo.CreateAsset(&dns.FQDN{Name: "example.com"})
// Wait a moment
time.Sleep(time.Second)
// Create same asset again
entity2, _ := repo.CreateAsset(&dns.FQDN{Name: "example.com"})
// entity1.ID == entity2.ID (same entity)
// entity2.LastSeen > entity1.LastSeen (updated timestamp)
Querying Entities¶
The repository provides multiple ways to find entities based on different criteria.
Query Methods Summary¶
| Method | Purpose | Returns |
|---|---|---|
FindEntityById(id) |
Find specific entity by ID | Single entity or error |
FindEntitiesByContent(asset, since) |
Find entities matching asset content | List of entities |
FindEntitiesByType(assetType, since) |
Find all entities of a specific type | List of entities |
Example: Finding Entity by ID¶
// Retrieve a specific entity
entity, err := repo.FindEntityById("entity-uuid-here")
if err != nil {
// Handle error (entity not found)
}
Example: Finding Entities by Content¶
import (
"time"
)
// Find all entities matching this FQDN
fqdn := &dns.FQDN{Name: "www.example.com"}
start := time.Now().Add(-24 * time.Hour) // Last 24 hours
entities, err := repo.FindEntitiesByContent(fqdn, start)
if err != nil {
// Handle error
}
// entities is a slice of all matching entities
for _, entity := range entities {
fmt.Printf("Found: %s\n", entity.ID)
}
Example: Finding Entities by Type¶
import (
oam "github.com/owasp-amass/open-asset-model"
)
// Find all FQDN entities
start := time.Now().Add(-7 * 24 * time.Hour) // Last 7 days
entities, err := repo.FindEntitiesByType(oam.FQDN, start)
if err != nil {
// Handle error
}
// Or find all IP addresses
ipEntities, err := repo.FindEntitiesByType(oam.IPAddress, start)
Working with Edges (Relationships)¶
Edges represent directed relationships between entities. Each edge has a source entity (FromEntity), a destination entity (ToEntity), and a relation type from the Open Asset Model.
Edge Creation Pattern¶
graph LR
FromEntity["types.Entity<br/>(source)"]
ToEntity["types.Entity<br/>(destination)"]
Relation["oam.Relation<br/>(BasicDNSRelation,<br/>SimpleRelation, etc.)"]
Edge["types.Edge"]
CreateEdge["CreateEdge(edge)"]
StoredEdge["types.Edge<br/>(with ID, timestamps)"]
FromEntity -->|FromEntity field| Edge
ToEntity -->|ToEntity field| Edge
Relation -->|Relation field| Edge
Edge -->|input| CreateEdge
CreateEdge -->|returns| StoredEdge
Example: Creating a DNS Relationship¶
import (
"github.com/owasp-amass/asset-db/types"
"github.com/owasp-amass/open-asset-model/dns"
)
// Create two FQDN entities
domain, _ := repo.CreateAsset(&dns.FQDN{Name: "example.com"})
subdomain, _ := repo.CreateAsset(&dns.FQDN{Name: "www.example.com"})
// Create a DNS record relationship
edge := &types.Edge{
Relation: &dns.BasicDNSRelation{
Name: "dns_record",
Header: dns.RRHeader{
RRType: 5, // CNAME record
Class: 1,
TTL: 3600,
},
},
FromEntity: domain,
ToEntity: subdomain,
}
createdEdge, err := repo.CreateEdge(edge)
if err != nil {
// Handle error
}
Example: Creating Simple Relationships¶
import (
"github.com/owasp-amass/open-asset-model/general"
)
// AS announces netblock
asEntity, _ := repo.CreateAsset(&network.AutonomousSystem{Number: 15169})
netblockEntity, _ := repo.CreateAsset(&network.Netblock{CIDR: cidr, Type: "IPv4"})
edge := &types.Edge{
Relation: &general.SimpleRelation{Name: "announces"},
FromEntity: asEntity,
ToEntity: netblockEntity,
}
createdEdge, err := repo.CreateEdge(edge)
Example: FQDN to IP Address Relationship¶
// FQDN resolves to IP address
fqdnEntity, _ := repo.CreateAsset(&dns.FQDN{Name: "www.domain.com"})
ipEntity, _ := repo.CreateAsset(&network.IPAddress{Address: ip, Type: "IPv4"})
edge := &types.Edge{
Relation: &dns.BasicDNSRelation{
Name: "dns_record",
Header: dns.RRHeader{RRType: 1}, // A record
},
FromEntity: fqdnEntity,
ToEntity: ipEntity,
}
createdEdge, err := repo.CreateEdge(edge)
Querying Edges¶
The repository provides methods to traverse the graph by finding incoming and outgoing edges for any entity.
Edge Query Methods¶
graph LR
Entity["types.Entity"]
Incoming["IncomingEdges(entity, since, labels...)"]
Outgoing["OutgoingEdges(entity, since, labels...)"]
InEdges["[]*types.Edge<br/>(edges pointing to entity)"]
OutEdges["[]*types.Edge<br/>(edges originating from entity)"]
Entity -->|query| Incoming
Entity -->|query| Outgoing
Incoming -->|returns| InEdges
Outgoing -->|returns| OutEdges
Example: Finding Outgoing Edges¶
// Find all edges originating from an entity
start := time.Now().Add(-24 * time.Hour)
// Get all outgoing edges (no label filter)
edges, err := repo.OutgoingEdges(sourceEntity, start)
if err != nil {
// Handle error
}
// Get only DNS record edges
dnsEdges, err := repo.OutgoingEdges(sourceEntity, start, "dns_record")
if err != nil {
// Handle error
}
for _, edge := range dnsEdges {
fmt.Printf("Edge from %s to %s\n",
edge.FromEntity.ID, edge.ToEntity.ID)
}
Example: Finding Incoming Edges¶
// Find all edges pointing to an entity
start := time.Now().Add(-24 * time.Hour)
// Get all incoming edges
edges, err := repo.IncomingEdges(destinationEntity, start)
if err != nil {
// Handle error
}
// Get only specific relation types
dnsEdges, err := repo.IncomingEdges(destinationEntity, start, "dns_record")
if err != nil {
// Handle error
}
for _, edge := range dnsEdges {
fmt.Printf("Edge from %s to %s\n",
edge.FromEntity.ID, edge.ToEntity.ID)
}
Example: Filtering Edges by Multiple Labels¶
// Query with multiple relation labels
edges, err := repo.OutgoingEdges(entity, start, "dns_record", "contains")
if err != nil {
// Handle error
}
// Query all relations (empty label list)
allEdges, err := repo.OutgoingEdges(entity, start)
Working with Tags (Properties)¶
Tags allow you to attach metadata (properties) to entities and edges. Each tag contains an Open Asset Model property and has its own lifecycle tracking (CreatedAt, LastSeen).
Tag Operations Flow¶
graph TB
Property["oam.Property<br/>(SimpleProperty,<br/>DNSRecordProperty, etc.)"]
Entity["types.Entity"]
Edge["types.Edge"]
CreateEntityProp["CreateEntityProperty(entity, property)"]
CreateEdgeProp["CreateEdgeProperty(edge, property)"]
EntityTag["types.EntityTag<br/>(with ID, timestamps)"]
EdgeTag["types.EdgeTag<br/>(with ID, timestamps)"]
GetEntityTags["GetEntityTags(entity, since, names...)"]
GetEdgeTags["GetEdgeTags(edge, since, names...)"]
Property -->|input| CreateEntityProp
Entity -->|input| CreateEntityProp
CreateEntityProp -->|returns| EntityTag
Property -->|input| CreateEdgeProp
Edge -->|input| CreateEdgeProp
CreateEdgeProp -->|returns| EdgeTag
Entity -->|query| GetEntityTags
Edge -->|query| GetEdgeTags
GetEntityTags -->|returns| EntityTag
GetEdgeTags -->|returns| EdgeTag
Example: Adding Properties to an Entity¶
import (
"github.com/owasp-amass/open-asset-model/general"
)
// Create an entity
entity, _ := repo.CreateAsset(&dns.FQDN{Name: "example.com"})
// Add a simple property
property := &general.SimpleProperty{
PropertyName: "source",
PropertyValue: "passive_dns",
}
tag, err := repo.CreateEntityProperty(entity, property)
if err != nil {
// Handle error
}
fmt.Printf("Tag ID: %s\n", tag.ID)
fmt.Printf("Property Name: %s\n", tag.Property.Name())
fmt.Printf("Property Value: %s\n", tag.Property.Value())
Example: Adding Properties to an Edge¶
// Create edge between entities
edge, _ := repo.CreateEdge(&types.Edge{
Relation: &dns.BasicDNSRelation{
Name: "dns_record",
Header: dns.RRHeader{RRType: 5},
},
FromEntity: sourceEntity,
ToEntity: destEntity,
})
// Add property to the edge
property := &general.SimpleProperty{
PropertyName: "resolver",
PropertyValue: "8.8.8.8",
}
tag, err := repo.CreateEdgeProperty(edge, property)
if err != nil {
// Handle error
}
Example: Retrieving Tags¶
// Get all tags for an entity
start := time.Now().Add(-24 * time.Hour)
allTags, err := repo.GetEntityTags(entity, start)
if err != nil {
// Handle error
}
// Get tags with specific property names
specificTags, err := repo.GetEntityTags(entity, start, "source", "confidence")
if err != nil {
// Handle error
}
for _, tag := range specificTags {
fmt.Printf("Property: %s = %s\n",
tag.Property.Name(), tag.Property.Value())
}
Tag Update Behavior¶
When you create a property that already exists (same name and value), the system updates the LastSeen timestamp. If you create a property with the same name but different value, it creates a new tag.
// Create initial property
prop1 := &general.SimpleProperty{
PropertyName: "status",
PropertyValue: "active",
}
tag1, _ := repo.CreateEntityProperty(entity, prop1)
time.Sleep(time.Second)
// Same property again - updates LastSeen
tag2, _ := repo.CreateEntityProperty(entity, prop1)
// tag1.ID == tag2.ID
// tag2.LastSeen > tag1.LastSeen
// Different value - creates new tag
prop1.PropertyValue = "inactive"
tag3, _ := repo.CreateEntityProperty(entity, prop1)
// tag3.ID != tag1.ID (new tag created)
Deleting Data¶
The repository provides methods to delete entities, edges, and tags.
Example: Deleting an Edge¶
Example: Deleting an Entity¶
err := repo.DeleteEntity(entityID)
if err != nil {
// Handle error
}
// Verify deletion
_, err = repo.FindEntityById(entityID)
// err will be non-nil (entity not found)
Example: Deleting Tags¶
// Delete entity tag
err := repo.DeleteEntityTag(tagID)
if err != nil {
// Handle error
}
// Delete edge tag
err = repo.DeleteEdgeTag(tagID)
if err != nil {
// Handle error
}
Complete Example: Building a Simple Asset Graph¶
This example demonstrates a typical workflow: creating entities, linking them with edges, and adding metadata.
package main
import (
"fmt"
"net/netip"
"time"
"github.com/owasp-amass/asset-db/repository"
"github.com/owasp-amass/asset-db/types"
"github.com/owasp-amass/open-asset-model/dns"
"github.com/owasp-amass/open-asset-model/general"
"github.com/owasp-amass/open-asset-model/network"
)
func main() {
// Initialize repository
repo, err := repository.New("sqlite", "example.db")
if err != nil {
panic(err)
}
defer repo.Close()
// Create an FQDN entity
fqdn, err := repo.CreateAsset(&dns.FQDN{Name: "www.example.com"})
if err != nil {
panic(err)
}
fmt.Printf("Created FQDN: %s\n", fqdn.ID)
// Create an IP address entity
ip, _ := netip.ParseAddr("192.0.2.1")
ipAddr, err := repo.CreateAsset(&network.IPAddress{
Address: ip,
Type: "IPv4",
})
if err != nil {
panic(err)
}
fmt.Printf("Created IP: %s\n", ipAddr.ID)
// Create DNS A record relationship
edge, err := repo.CreateEdge(&types.Edge{
Relation: &dns.BasicDNSRelation{
Name: "dns_record",
Header: dns.RRHeader{
RRType: 1, // A record
TTL: 300,
},
},
FromEntity: fqdn,
ToEntity: ipAddr,
})
if err != nil {
panic(err)
}
fmt.Printf("Created edge: %s\n", edge.ID)
// Add metadata to the FQDN
sourceTag, err := repo.CreateEntityProperty(fqdn, &general.SimpleProperty{
PropertyName: "source",
PropertyValue: "certificate_transparency",
})
if err != nil {
panic(err)
}
fmt.Printf("Added tag: %s\n", sourceTag.ID)
// Query all outgoing edges from the FQDN
start := time.Now().Add(-1 * time.Hour)
edges, err := repo.OutgoingEdges(fqdn, start)
if err != nil {
panic(err)
}
fmt.Printf("\nFound %d outgoing edges\n", len(edges))
for _, e := range edges {
fmt.Printf(" Edge: %s -> %s (%s)\n",
e.FromEntity.ID,
e.ToEntity.ID,
e.Relation.Label())
}
// Query tags on the FQDN
tags, err := repo.GetEntityTags(fqdn, start)
if err != nil {
panic(err)
}
fmt.Printf("\nFound %d tags\n", len(tags))
for _, tag := range tags {
fmt.Printf(" %s = %s\n",
tag.Property.Name(),
tag.Property.Value())
}
}