// Command icims-sync runs one incremental sync of a pilot tenant's iCIMS ATS into the candidates table. It // pulls candidates updated since the org's stored watermark, ingests each as a structured candidate (skills, // certs, agencies as rows) plus a sourcing_log provenance row through the proven sourcing path, and advances the // watermark, so a scheduled run (a systemd timer, like mm-opp-sync) keeps the bench fresh from the customer's // own ATS. Clearance stays unknown (sourced clearance is never a held clearance). It runs as the BYPASSRLS // migrator role with an explicit org, exactly like import-candidates. // // Env (server side only): MM_MIGRATOR_DATABASE_URL (or MM_DATABASE_URL); ICIMS_CUSTOMER_ID, ICIMS_CLIENT_ID, // ICIMS_CLIENT_SECRET (the OAuth client credentials); ICIMS_API_BASE (optional override); MM_DEMO_ORG_ID (or the // -org flag). Flags: -org, -max (the per run record cap), -legal-basis. // // Build and run FIPS validated: CGO_ENABLED=0 GOFIPS140=v1.0.0 go build, run with GODEBUG=fips140=on. package main import ( "context" "crypto/fips140" "crypto/pbkdf2" "crypto/sha256" "errors" "flag" "log" "os" "strings" "time" "github.com/google/uuid" "github.com/missionworkforce/missionmatch/internal/platform/connector" "github.com/missionworkforce/missionmatch/internal/platform/database" "github.com/missionworkforce/missionmatch/internal/platform/extraction" "github.com/missionworkforce/missionmatch/internal/platform/sourcing" ) const defaultOrg = "11111111-1111-1111-1111-111111111111" func main() { orgFlag := flag.String("org", "", "the organization uuid to sync (default MM_DEMO_ORG_ID)") maxRecords := flag.Int("max", 1000, "the per run record cap (a large backfill degrades gracefully)") legalBasis := flag.String("legal-basis", "Customer provided workforce data ingested from the customer's own iCIMS ATS under the service agreement", "the lawful basis recorded in the sourcing_log for each record") flag.Parse() if err := fipsSelfTest(); err != nil { log.Fatalf("icims-sync: FIPS self test (PBKDF2 HMAC SHA 256) failed: %v", err) } log.Printf("icims-sync: fips_enabled=%v module=%s", fips140.Enabled(), fips140.Version()) ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) defer cancel() dsn := firstNonEmpty(os.Getenv("MM_MIGRATOR_DATABASE_URL"), os.Getenv("MM_DATABASE_URL")) if dsn == "" { log.Fatal("icims-sync: set MM_MIGRATOR_DATABASE_URL (the BYPASSRLS migrator DSN)") } customerID := strings.TrimSpace(os.Getenv("ICIMS_CUSTOMER_ID")) clientID := strings.TrimSpace(os.Getenv("ICIMS_CLIENT_ID")) clientSecret := strings.TrimSpace(os.Getenv("ICIMS_CLIENT_SECRET")) if customerID == "" || clientID == "" || clientSecret == "" { log.Fatal("icims-sync: set ICIMS_CUSTOMER_ID, ICIMS_CLIENT_ID, ICIMS_CLIENT_SECRET (server side env only)") } orgStr := firstNonEmpty(*orgFlag, os.Getenv("MM_DEMO_ORG_ID"), defaultOrg) orgID, err := uuid.Parse(orgStr) if err != nil { log.Fatalf("icims-sync: bad org id %q: %v", orgStr, err) } pool, err := database.NewPool(ctx, dsn) if err != nil { log.Fatalf("icims-sync: db connect: %v", err) } defer pool.Close() if err := database.AssertMigratorRole(ctx, pool); err != nil { log.Fatalf("icims-sync: %v", err) } ext := extraction.NewDeterministic() // certs and agencies from the profile text; skills come structured c := connector.NewICIMS(customerID, clientID, clientSecret, os.Getenv("ICIMS_API_BASE"), nil) log.Printf("icims-sync: connector=%q org=%s max=%d", c.Name(), orgID, *maxRecords) res, err := connector.Sync(ctx, pool, orgID, c, ext, *legalBasis, *maxRecords) if err != nil { if errors.Is(err, sourcing.ErrThrottled) { log.Printf("icims-sync: provider rate limited (429) after %d records over %d pages; watermark advanced to %s, stopping gracefully", res.Synced, res.Pages, res.Watermark.UTC().Format(time.RFC3339)) return } log.Fatalf("icims-sync: sync: %v", err) } log.Printf("icims-sync: DONE, ingested %d candidates over %d pages; watermark advanced to %s", res.Synced, res.Pages, res.Watermark.UTC().Format(time.RFC3339)) } // fipsSelfTest derives one PBKDF2 HMAC SHA 256 key under the active crypto module and fails closed if it errors. func fipsSelfTest() error { _, err := pbkdf2.Key(sha256.New, "icims-sync-self-test", []byte("icims-sync-salt"), 600000, 32) return err } func firstNonEmpty(vals ...string) string { for _, v := range vals { if s := strings.TrimSpace(v); s != "" { return s } } return "" }