Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / cmd/oews-national-sync/main.go |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | cmd/oews-national-sync/main.go |
| Original SHA-256 | 1ec58d32debdbbe267b73f6a95073c9b5fe7615931fc81c61757d0ef515b0188 |
| Git blob SHA | 782dc72573ee1044835bde1e88c92642c9d3e737 |
| Reading-copy SHA-256 | 1ec58d32debdbbe267b73f6a95073c9b5fe7615931fc81c61757d0ef515b0188 |
Every recorded occurrence
These 11 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / cmd/oews-national-sync/main.go | feature/opportunity-to-outcome | 720d47fae476b0d38477ae4401697d372b1ea2bc | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
| Janady13/missionmatch / cmd/oews-national-sync/main.go | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓207 lines · 8.3 KB
// Command oews-national-sync expands the BLS OEWS wage baseline to ALL detailed SOC occupations at the US
// NATIONAL level (M5 price to win Phase 1). The existing rates sync (cmd/rates-sync) writes the Galapagos
// HI and NM state rows; this job writes a national US row for every detailed OEWS occupation so any
// requirement whose title resolves to a SOC gets at least the national wage band even outside HI and NM.
//
// It downloads the BLS oe.occupation flat file (with the required descriptive User Agent that names a
// contact email, since BLS returns 403 to a default User Agent), keeps the detailed SOCs (display level
// 3, roughly 800), builds the two national series per SOC (OEUN...04 annual mean, OEUN...13 annual
// median), pulls the latest annual value in batches of 50 through the shared BLS client, and upserts one
// row per (occupation_code, area='US', metric) into the global public bls_wages catalog. It is idempotent:
// a second run updates values and inserts nothing new. Roughly 800 SOCs times 2 datatypes is about 1600
// series, about 32 batched API requests, well inside the BLS 500 request daily limit.
//
// The national rows carry area='US', area_name='United States', and an empty role (national data has no
// Galapagos role); the HI and NM Galapagos state rows the rates sync writes are complementary and untouched.
//
// Env: BLS_API_KEY (server side only, never logged) and MM_MIGRATOR_DATABASE_URL (or MM_DATABASE_URL, the
// migrator DSN, since bls_wages is a global catalog the app role may only read). Optional: BLS_API_BASE
// (override the API endpoint), BLS_OCCUPATION_URL (override the flat file URL), BLS_USER_AGENT (override
// the descriptive User Agent). 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"
"log"
"net/http"
"os"
"strings"
"time"
"github.com/jackc/pgx/v5/pgxpool"
"github.com/shopspring/decimal"
"github.com/missionworkforce/missionmatch/internal/platform/bls"
"github.com/missionworkforce/missionmatch/internal/platform/database"
"github.com/missionworkforce/missionmatch/internal/platform/database/dbgen"
)
// defaultUserAgent is the descriptive User Agent naming a contact email, required by the BLS download.
const defaultUserAgent = "missionMATCH wage sync (joseph.w.anady@gmail.com)"
// batchPause is a small courtesy sleep between BLS API batches so the sync is a good API citizen.
const batchPause = 500 * time.Millisecond
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Minute)
defer cancel()
// FIPS self test: derive one PBKDF2 HMAC SHA 256 key under the active crypto module and fail closed if
// it errors, so a build that dropped the validated module is caught at boot, the same in build FIPS gate
// the api and rates sync binaries use.
if err := fipsSelfTest(); err != nil {
log.Fatalf("oews-national-sync: FIPS self test (PBKDF2 HMAC SHA 256) failed: %v", err)
}
log.Printf("oews-national-sync: fips_enabled=%v module=%s", fips140.Enabled(), fips140.Version())
key := strings.TrimSpace(os.Getenv("BLS_API_KEY"))
dsn := firstNonEmpty(os.Getenv("MM_MIGRATOR_DATABASE_URL"), os.Getenv("MM_DATABASE_URL"))
if key == "" {
log.Fatal("oews-national-sync: BLS_API_KEY not set (server side env only)")
}
if dsn == "" {
log.Fatal("oews-national-sync: set MM_MIGRATOR_DATABASE_URL (or MM_DATABASE_URL)")
}
userAgent := firstNonEmpty(os.Getenv("BLS_USER_AGENT"), defaultUserAgent)
occURL := firstNonEmpty(os.Getenv("BLS_OCCUPATION_URL"), bls.OccupationListURL)
pool, err := pgxpool.New(ctx, dsn)
if err != nil {
log.Fatalf("oews-national-sync: db connect: %v", err)
}
defer pool.Close()
if err := pool.Ping(ctx); err != nil {
log.Fatalf("oews-national-sync: db ping: %v", err)
}
// bls_wages is a global catalog the application role may only read, so this writer needs the BYPASSRLS
// migrator DSN; assert it now for a legible failure instead of a mid run permission denied.
if err := database.AssertMigratorRole(ctx, pool); err != nil {
log.Fatalf("oews-national-sync: %v", err)
}
q := dbgen.New(pool)
// Phase 1: download and parse the detailed OEWS occupations (display level 3).
occs, err := bls.FetchDetailedOccupations(ctx, &http.Client{Timeout: 90 * time.Second}, occURL, userAgent)
if err != nil {
log.Fatalf("oews-national-sync: download occupation list: %v", err)
}
if len(occs) == 0 {
log.Fatal("oews-national-sync: the occupation list held no detailed SOCs; refusing to proceed")
}
log.Printf("oews-national-sync: detailed OEWS occupations found=%d", len(occs))
// Phase 2: build the two national series per SOC and index them by series id so the fetched value maps
// back to its occupation and metric.
byID := make(map[string]bls.SeriesSpec, len(occs)*len(bls.Metrics))
ids := make([]string, 0, len(occs)*len(bls.Metrics))
for _, o := range occs {
for _, spec := range bls.NationalSeries(o.SOC, o.Title) {
byID[spec.SeriesID] = spec
ids = append(ids, spec.SeriesID)
}
}
log.Printf("oews-national-sync: national series to query=%d (about %d batched requests)", len(ids), (len(ids)+49)/50)
// Phase 3: fetch the latest annual value per series, batched 50 per request with a courtesy pause, then
// upsert. FetchLatest already batches at 50; wrap it per batch so a courtesy pause sits between batches
// and a No Data series is simply absent (the client skips an empty data series).
series, err := fetchBatched(ctx, bls.New(key, os.Getenv("BLS_API_BASE")), ids)
if err != nil {
if errors.Is(err, bls.ErrThrottled) {
log.Printf("oews-national-sync: BLS daily threshold reached, stopping run gracefully")
return
}
log.Fatalf("oews-national-sync: fetch: %v", err)
}
log.Printf("oews-national-sync: series returned with data=%d", len(series))
// Phase 4: upsert one national row per (occupation_code, area='US', metric). A series with No Data is
// absent from the results, so it is skipped without failing the run.
upserted := 0
skippedNoValue := 0
for _, s := range series {
spec, ok := byID[s.ID]
if !ok {
continue
}
var val *decimal.Decimal
if v, err := decimal.NewFromString(strings.TrimSpace(s.Value)); err == nil {
val = &v
} else {
skippedNoValue++
continue // an unparseable value is not written; the honest floor holds for that occupation
}
raw := []byte(`{"series_id":"` + s.ID + `","year":"` + s.Year + `","value":"` + s.Value + `"}`)
if err := q.UpsertBlsWageByOcc(ctx, dbgen.UpsertBlsWageByOccParams{
SeriesID: s.ID,
OccupationCode: spec.OccCode,
OccupationTitle: spec.OccTitle,
Role: spec.Role,
Area: spec.Area,
AreaName: spec.AreaName,
Metric: spec.Metric,
PeriodYear: s.Year,
Value: val,
Raw: raw,
}); err != nil {
log.Printf("oews-national-sync: upsert %s: %v", s.ID, err)
continue
}
upserted++
}
total := int64(-1)
if meta, err := q.WagesSyncMeta(ctx); err == nil {
total = meta.Total
}
log.Printf("oews-national-sync: DONE, occupations=%d series_queried=%d rows_upserted=%d skipped_no_value=%d; store holds %d wage series",
len(occs), len(ids), upserted, skippedNoValue, total)
}
// fetchBatched pulls the latest data point for each series in batches of 50, pausing briefly between
// batches so the sync is a good API citizen. A No Data series is simply absent from a batch's results.
func fetchBatched(ctx context.Context, client *bls.Client, ids []string) ([]bls.Series, error) {
const batch = 50
var out []bls.Series
for start := 0; start < len(ids); start += batch {
end := start + batch
if end > len(ids) {
end = len(ids)
}
got, err := client.FetchLatest(ctx, ids[start:end])
if err != nil {
return out, err
}
out = append(out, got...)
if end < len(ids) {
select {
case <-ctx.Done():
return out, ctx.Err()
case <-time.After(batchPause):
}
}
}
return out, nil
}
// fipsSelfTest derives one PBKDF2 HMAC SHA 256 key under the active crypto module. It fails closed if the
// module is absent or errors, so a non FIPS build is caught at boot.
func fipsSelfTest() error {
_, err := pbkdf2.Key(sha256.New, "oews-national-sync-self-test", []byte("oews-national-sync-salt"), 600000, 32)
return err
}
func firstNonEmpty(vals ...string) string {
for _, v := range vals {
if s := strings.TrimSpace(v); s != "" {
return s
}
}
return ""
}