
    W՞il                        d Z ddlmZ ddlZddlZddlZddlZdZdZh dZ	ddZ
ddZdd	Zdd
ZdddZedk(  r e        yy)u  
scripts/migrate_secrets.py
Migrate secrets from config/secrets.env to Infisical.

Usage:
    python3 scripts/migrate_secrets.py --dry-run     # Preview — no API calls
    python3 scripts/migrate_secrets.py --execute     # Upload to Infisical

Side-effects (always, regardless of mode):
    Writes config/secrets.env.template with placeholder values so the
    plaintext file can safely be removed or gitignored.

Environment variables required for --execute:
    INFISICAL_TOKEN       — Universal Auth client secret
    INFISICAL_PROJECT_ID  — Infisical project UUID

# VERIFICATION_STAMP
# Story: M1.03 — scripts/migrate_secrets.py
# Verified By: parallel-builder
# Verified At: 2026-02-25
# Tests: 16/16
# Coverage: 100%
    )annotationsNz(/mnt/e/genesis-system/config/secrets.envz1/mnt/e/genesis-system/config/secrets.env.template>   N8N_API_KEYGEMINI_API_KEYGOOGLE_API_KEYTELNYX_API_KEYANTHROPIC_API_KEYOPENROUTER_API_KEYGENESIS_PG_PASSWORDVAPI_PUBLIC_API_KEYVAPI_PRIVATE_API_KEYCLAUDE_GENESIS_API_KEYGENESIS_QDRANT_API_KEYGENESIS_REDIS_PASSWORDNEW_GENESIS_GEMINI_API_KEYELEVENLABS_AGILEADAPT_API_KEYc                t   i }t        | dd      5 }|D ]  }|j                         }|r|j                  d      r't        j                  d|      }|s@|j                  d      }|j                  d      }t        |      dk\  r|d   |d	   k(  r|d   d
v r|dd	 }|||<    	 ddd       |S # 1 sw Y   |S xY w)uQ  
    Parse a .env file into a ``{key: value}`` dict.

    Rules:
    - Lines starting with ``#`` are comments → skipped
    - Blank lines → skipped
    - Values may be bare, single-quoted, or double-quoted
    - Inline comments (``KEY=VALUE  # comment``) are NOT stripped
      (preserves values that legitimately contain ``#``)
    rutf-8encoding#z^([A-Za-z_][A-Za-z0-9_]*)=(.*)$      r   )"'N)openstrip
startswithrematchgrouplen)pathsecretsfhraw_lineliner!   key	raw_values           0/mnt/e/genesis-system/scripts/migrate_secrets.pyparse_env_filer,   9   s     !G	dC'	* )b 	)H>>#D4??3/HH?FEkk!n!KKN	 	Na'!!	"5!!
2 )!BI(	))" N#)" Ns   AB-AB--B7c           	     >   g d}t        | j                               D ]7  }|j                  | d|j                         j	                  dd       d       9 t        |dd      5 }|j                  d	j                  |      d	z          d
d
d
       y
# 1 sw Y   y
xY w)z.Write a .env.template with placeholder values.)z# Genesis Secrets Templatez.# Copy to secrets.env and fill in real values.z[# Production secret management: use Infisical (set INFISICAL_TOKEN + INFISICAL_PROJECT_ID).z.# NEVER commit secrets.env to version control. z=<your-_-z-here>wr   r   
N)sortedkeysappendlowerreplacer   writejoin)r%   output_pathlinesr)   r&   s        r+   generate_templater<   ]   s    E glln% KuGCIIK$7$7S$A#B&IJK	k3	1 *R
5!D()* * *s   &$BBc                D    | t         v ryt        |      dkD  r|dd dz   S |S )z0Return a display-safe representation of *value*.z***REDACTED***   N   z...)_HIGH_SENSITIVITYr#   )r)   values     r+   _preview_valuerB   p   s/    

5zBRay5  L    c           
     l   	 ddl m} t        j                  j                  d      }t        j                  j                  d      }|s t        d       t	        j
                  d       |s t        d	       t	        j
                  d       t        d
| d        d      }|j                  j                  j                  ||       d}d}| j                         D ]8  \  }}	 |j                  j                  |||d       t        d|        |dz  }: t        d| d| dt!        |        d       |rt	        j
                  d       yy# t        $ r/ t        d       t        d       t	        j
                  d       Y ~w xY w# t        $ r }	t        d| d|	        |dz  }Y d}	~	d}	~	ww xY w)z<Upload all parsed secrets to Infisical using Universal Auth.r   )InfisicalSDKClientz#ERROR: infisical_sdk not installed.z(       Run: pip install infisical-pythonr   INFISICAL_TOKENINFISICAL_PROJECT_IDz7ERROR: INFISICAL_TOKEN environment variable is not set.z<ERROR: INFISICAL_PROJECT_ID environment variable is not set.z!Connecting to Infisical (project=u   ) …zhttps://app.infisical.com)host)	client_idclient_secretprod)secret_namesecret_value
project_idenvironment_slugz
  [OK]    z
  [FAIL]  u    — Nz	
Result: z uploaded, z failed out of z total.)infisical_sdkrE   ImportErrorprintsysexitosenvirongetauthuniversal_authloginitemsr%   create_secret_by_name	Exceptionr#   )
r%   rE   tokenrN   clientuploadedfailedr)   rA   excs
             r+   upload_to_infisicalrc   }   s   4 JJNN,-E 67JGHLM	-j\
?@%@AF
KK$$z$OHFmmo 
U	NN00"%!'	 1  Jse$%MH 
JxjF8?3w<.PW
XY G  3489<  	Jse5./aKF	s)   E $2F
4FF
	F3F..F3c                   t        j                  dt         j                  t              }|j	                  d      }|j                  ddd       |j                  d	dd
       |j                  |       }t        j                  j                  t              s't        dt                t        j                  d       t        t              }t        dt        |       dt                t!        |t"               t        dt"                |j$                  r`t        d       t'        |j)                               D ]   }t        d| dt+        |||                 " t        dt        |       d       y t-        |       y )Nz=Migrate Genesis secrets from config/secrets.env to Infisical.)descriptionformatter_classepilogT)requiredz	--dry-run
store_truez6Preview secrets that would be uploaded (no API calls).)actionhelpz	--executezNUpload secrets to Infisical (requires INFISICAL_TOKEN + INFISICAL_PROJECT_ID).zERROR: secrets file not found: r   zParsed z secrets from zTemplate written to u0   
--- DRY RUN — no secrets will be uploaded ---z  z = z
Total: z/ secrets would be uploaded to Infisical (prod).)argparseArgumentParserRawDescriptionHelpFormatter__doc__add_mutually_exclusive_groupadd_argument
parse_argsrU   r$   existsSECRETS_FILErR   rS   rT   r,   r#   r<   TEMPLATE_FILEdry_runr3   r4   rB   rc   )argvparserr"   argsr%   r)   s         r+   mainrz      s\   $$S <<F
 ///>E	E  
 
]  
 T"D77>>,'/~>?\*G	GCL>~
>? g}-	 
01||AB',,.) 	DCBse3~c73<@ABC	D	#g,'VWX  rC   __main__)r$   strreturndict[str, str])r%   r~   r:   r|   r}   None)r)   r|   rA   r|   r}   r|   )r%   r~   r}   r   )N)rw   zlist[str] | Noner}   r   )ro   
__future__r   rl   rU   r    rS   rt   ru   r@   r,   r<   rB   rc   rz   __name__ rC   r+   <module>r      s]   . #  	 	 
9C ,H*&(^&!R zF rC   