Skip to content

Commit fcd642d

Browse files
authored
Merge pull request #47 from ConductorOne/feature/employee-id-and-last-login
[BB-536][BB-537] Add employee ID and last login support
2 parents 1ad6a12 + d1b8ca9 commit fcd642d

18 files changed

+1545
-0
lines changed

CLAUDE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Build, Test, and Lint Commands
6+
- Build: `make build` - Builds the baton-sql binary
7+
- Run tests: `go test ./...` - Run all tests
8+
- Run specific test: `go test ./pkg/path/to/package -run TestName`
9+
- Run tests with verbose output: `go test -v ./...`
10+
- Lint: `make lint` - Runs golangci-lint
11+
12+
## Code Style Guidelines
13+
- Error handling: Use `fmt.Errorf` with context; check specific errors with `errors.Is`
14+
- Imports: Standard lib first, then third-party, then project imports, alphabetized within groups
15+
- Naming: CamelCase for exported, camelCase for unexported; special handling for ID, URL, HTTP, API
16+
- Tests: Table-driven tests with testify/require; format TestStructName_methodName
17+
- Line length: Maximum 200 characters
18+
- Comments: Complete sentences ending with periods for exported items
19+
- Absolutely no usage of log.Fatal or log.Panic (enforced by ruleguard)

Dockerfile.test

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
FROM golang:1.24-alpine as builder
2+
3+
WORKDIR /app
4+
5+
# Copy go mod files
6+
COPY go.mod go.sum ./
7+
RUN go mod download
8+
9+
# Copy source code
10+
COPY . .
11+
12+
# Build the application
13+
RUN go build -o baton-sql ./cmd/baton-sql
14+
15+
# Create final container
16+
FROM alpine:3.18
17+
18+
RUN apk add --no-cache ca-certificates bash curl
19+
20+
WORKDIR /app
21+
22+
# Copy binary from builder
23+
COPY --from=builder /app/baton-sql .
24+
25+
# Default command
26+
CMD ["/app/baton-sql"]

docker-compose-postgres-test.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
services:
2+
# PostgreSQL Database for testing employee_id and last_login features
3+
postgres:
4+
image: postgres:14
5+
container_name: baton-postgres-test
6+
environment:
7+
POSTGRES_USER: baton
8+
POSTGRES_PASSWORD: password
9+
POSTGRES_DB: batondb
10+
ports:
11+
- "5432:5432"
12+
volumes:
13+
- ./test/postgres-init.sql:/docker-entrypoint-initdb.d/init.sql
14+
healthcheck:
15+
test: ["CMD", "pg_isready", "-U", "baton"]
16+
interval: 5s
17+
timeout: 5s
18+
retries: 5
19+
20+
# Connector test container
21+
baton-sql-test:
22+
build:
23+
context: .
24+
dockerfile: Dockerfile.test
25+
container_name: baton-sql-postgres-test
26+
depends_on:
27+
postgres:
28+
condition: service_healthy
29+
volumes:
30+
- ./examples:/examples
31+
- ./test:/test
32+
command: >
33+
/bin/bash -c "
34+
# Wait for PostgreSQL to be fully ready
35+
sleep 5
36+
# Run the baton-sql connector with PostgreSQL test configuration
37+
/app/baton-sql --config-path /examples/postgres-test.yml --log-level debug
38+
"

docker-compose-test.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
services:
2+
# MySQL Database for testing employee_id and last_login features
3+
mysql:
4+
image: mysql:8.0
5+
container_name: baton-mysql-test
6+
environment:
7+
MYSQL_ROOT_PASSWORD: rootpassword
8+
MYSQL_DATABASE: batondb
9+
MYSQL_USER: baton
10+
MYSQL_PASSWORD: password
11+
ports:
12+
- "3306:3306"
13+
volumes:
14+
- ./test/mysql-init.sql:/docker-entrypoint-initdb.d/init.sql
15+
healthcheck:
16+
test: ["CMD", "mysql", "-ubaton", "-ppassword", "-e", "SELECT 1"]
17+
interval: 5s
18+
timeout: 5s
19+
retries: 5
20+
21+
# Connector test container
22+
baton-sql-test:
23+
build:
24+
context: .
25+
dockerfile: Dockerfile.test
26+
container_name: baton-sql-test
27+
depends_on:
28+
mysql:
29+
condition: service_healthy
30+
volumes:
31+
- ./examples:/examples
32+
- ./test:/test
33+
command: >
34+
/bin/bash -c "
35+
# Wait for MySQL to be fully ready
36+
sleep 5
37+
# Run the baton-sql connector with test configuration
38+
/app/baton-sql --config-path /examples/mysql-test.yml --log-level debug
39+
"

examples/mysql-local-test.yml

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
---
2+
# Application name for this connector configuration
3+
app_name: MySQL Local Test
4+
app_description: Test configuration for MySQL with employee_id and last_login support (for local testing)
5+
6+
# Connection settings for the MySQL database
7+
connect:
8+
# Data Source Name (DSN) for our local MySQL instance running in Docker
9+
dsn: "mysql://baton:password@localhost:3306/batondb"
10+
11+
# Definition of different resource types managed by this connector
12+
resource_types:
13+
# Configuration for "user" resources in MySQL
14+
user:
15+
# Display name for this resource type
16+
name: "User"
17+
# Description providing context about what a user represents
18+
description: "A user within the MySQL system"
19+
# Settings for listing user records from the database
20+
list:
21+
# SQL query to fetch user-related data including employee_id, last_login, and manager information
22+
query: |
23+
SELECT
24+
u.id,
25+
u.username,
26+
u.email,
27+
u.employee_id,
28+
u.status,
29+
u.account_type,
30+
u.created_at,
31+
u.last_login,
32+
u.manager_id,
33+
m.username as manager_username,
34+
m.email as manager_email
35+
FROM
36+
users u
37+
LEFT JOIN
38+
users m ON u.manager_id = m.id
39+
# Pagination configuration (using offset for MySQL)
40+
pagination:
41+
strategy: "offset"
42+
primary_key: "id"
43+
# Mapping of query results to resource fields
44+
map:
45+
# Unique identifier for the user resource
46+
id: ".username"
47+
# Field to display as the resource's name
48+
display_name: ".username"
49+
# Additional description for the user resource
50+
description: ".username"
51+
# Extra attributes (traits) for the user resource
52+
traits:
53+
user:
54+
# Map status from database (active, disabled) to proper resource status
55+
status: ".status"
56+
# Login identifier - username
57+
login: ".username"
58+
# Email addresses
59+
emails:
60+
- ".email"
61+
# Account type mapping
62+
account_type: ".account_type"
63+
# Employee ID mapping
64+
employee_ids:
65+
- ".employee_id"
66+
# Last login timestamp mapping
67+
last_login: ".last_login"
68+
# Manager information
69+
manager_id: ".manager_id"
70+
manager_email: ".manager_email"
71+
72+
# Profile details for the user
73+
profile:
74+
user_id: ".id"
75+
created_at: ".created_at"
76+
last_login: ".last_login"
77+
manager_id: ".manager_id"
78+
manager_username: ".manager_username"
79+
manager_email: ".manager_email"
80+
81+
# Configuration for "role" resources
82+
role:
83+
# Display name for the role resource type
84+
name: "Role"
85+
# Brief description of what a role signifies
86+
description: "A role within the MySQL system"
87+
# Settings for listing roles from the database
88+
list:
89+
# SQL query to retrieve roles
90+
query: |
91+
SELECT
92+
id,
93+
role_name
94+
FROM
95+
roles
96+
# Pagination configuration
97+
pagination:
98+
strategy: "offset"
99+
primary_key: "id"
100+
# Mapping of each query result to role resource fields
101+
map:
102+
# Unique role identifier
103+
id: ".role_name"
104+
# Display name for the role
105+
display_name: ".role_name"
106+
# Role description
107+
description: ".role_name"
108+
# Additional role-specific traits
109+
traits:
110+
role:
111+
# Profile mapping for the role
112+
profile:
113+
role_id: ".id"
114+
115+
# Define a static entitlement for role membership
116+
static_entitlements:
117+
- id: "member"
118+
display_name: "'Member'"
119+
description: "'Role member'"
120+
purpose: "assignment"
121+
grantable_to:
122+
- "user"
123+
124+
# Dynamic grants based on SQL queries to associate users with roles
125+
grants:
126+
- query: |
127+
SELECT
128+
u.username,
129+
r.role_name
130+
FROM
131+
users u
132+
JOIN
133+
user_roles ur ON u.id = ur.user_id
134+
JOIN
135+
roles r ON r.id = ur.role_id
136+
pagination:
137+
strategy: "offset"
138+
primary_key: "username"
139+
map:
140+
- skip_if: ".role_name != resource.ID"
141+
principal_id: ".username"
142+
principal_type: "user"
143+
entitlement_id: "member"

0 commit comments

Comments
 (0)