codecrypto-cli 1.0.20 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/deploy-mcp.d.ts.map +1 -1
- package/dist/commands/deploy-mcp.js +156 -1
- package/dist/commands/deploy-mcp.js.map +1 -1
- package/dist/commands/deploy.d.ts.map +1 -1
- package/dist/commands/deploy.js +156 -1
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +199 -14
- package/dist/commands/doctor.js.map +1 -1
- package/package.json +1 -1
- package/src/commands/deploy-mcp.ts +182 -1
- package/src/commands/deploy.ts +182 -1
- package/src/commands/doctor.ts +206 -19
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
4
5
|
import { execSync, spawn } from 'child_process';
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import * as path from 'path';
|
|
@@ -59,7 +60,9 @@ export const deployMcpCommand = new Command('deploy-mcp')
|
|
|
59
60
|
projectName = path.basename(resolvedProjectPath).toLowerCase().replace(/[^a-z0-9._-]/g, '-');
|
|
60
61
|
}
|
|
61
62
|
|
|
62
|
-
|
|
63
|
+
// Obtener el prefijo de imagen desde Docker config o solicitar por teclado
|
|
64
|
+
const dockerHubUsername = await getDockerHubUsernameFromToken();
|
|
65
|
+
const imageBase = `${dockerHubUsername}/${projectName}`;
|
|
63
66
|
const imageName = `${imageBase}:${version}`;
|
|
64
67
|
const imageLatest = `${imageBase}:latest`;
|
|
65
68
|
|
|
@@ -562,6 +565,184 @@ echo "✅ Deployment preparation completed inside container"
|
|
|
562
565
|
}
|
|
563
566
|
});
|
|
564
567
|
|
|
568
|
+
// Función para obtener el username de Docker Hub desde Docker config o solicitar por teclado
|
|
569
|
+
async function getDockerHubUsernameFromToken(): Promise<string> {
|
|
570
|
+
// Obtener el username desde Docker config (requerido para poder hacer push)
|
|
571
|
+
const dockerConfigPath = path.join(os.homedir(), '.docker', 'config.json');
|
|
572
|
+
|
|
573
|
+
if (!fs.existsSync(dockerConfigPath)) {
|
|
574
|
+
throw new Error(
|
|
575
|
+
'Docker authentication not found. Please login to Docker first.\n' +
|
|
576
|
+
' Run: docker login\n' +
|
|
577
|
+
' This is required to push images to Docker Hub.'
|
|
578
|
+
);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
try {
|
|
582
|
+
const dockerConfig = JSON.parse(fs.readFileSync(dockerConfigPath, 'utf-8'));
|
|
583
|
+
|
|
584
|
+
// Verificar si hay credsStore (las credenciales están en el keychain del sistema)
|
|
585
|
+
const hasCredsStore = dockerConfig.credsStore && dockerConfig.credsStore !== '';
|
|
586
|
+
|
|
587
|
+
// Buscar username en Docker Hub auth
|
|
588
|
+
let dockerHubKeys: string[] = [];
|
|
589
|
+
if (dockerConfig.auths && Object.keys(dockerConfig.auths).length > 0) {
|
|
590
|
+
dockerHubKeys = Object.keys(dockerConfig.auths).filter(reg =>
|
|
591
|
+
reg.includes('docker.io') ||
|
|
592
|
+
reg.includes('hub.docker.com') ||
|
|
593
|
+
reg === 'https://index.docker.io/v1/'
|
|
594
|
+
);
|
|
595
|
+
|
|
596
|
+
// Si hay credsStore, los auths pueden estar vacíos pero las credenciales están en el keychain
|
|
597
|
+
if (hasCredsStore && dockerHubKeys.length > 0) {
|
|
598
|
+
// Intentar obtener username desde docker info
|
|
599
|
+
try {
|
|
600
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
601
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
602
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
603
|
+
let username = usernameMatch[1].trim();
|
|
604
|
+
|
|
605
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
606
|
+
if (username.includes('@')) {
|
|
607
|
+
username = username.split('@')[0];
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Sanitizar el username para Docker Hub
|
|
611
|
+
username = username.toLowerCase()
|
|
612
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
613
|
+
.replace(/^-+|-+$/g, '')
|
|
614
|
+
.replace(/-+/g, '-')
|
|
615
|
+
.replace(/\.+/g, '.')
|
|
616
|
+
.substring(0, 30);
|
|
617
|
+
|
|
618
|
+
if (username) {
|
|
619
|
+
return username;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
} catch (infoError) {
|
|
623
|
+
// Si docker info falla, continuar con otros métodos
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Si no hay credsStore, buscar username directamente en auths
|
|
628
|
+
if (!hasCredsStore) {
|
|
629
|
+
for (const key of dockerHubKeys) {
|
|
630
|
+
const authData = dockerConfig.auths[key];
|
|
631
|
+
if (authData && authData.username) {
|
|
632
|
+
let username = authData.username;
|
|
633
|
+
|
|
634
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
635
|
+
if (username.includes('@')) {
|
|
636
|
+
username = username.split('@')[0];
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Sanitizar el username para Docker Hub
|
|
640
|
+
username = username.toLowerCase()
|
|
641
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
642
|
+
.replace(/^-+|-+$/g, '')
|
|
643
|
+
.replace(/-+/g, '-')
|
|
644
|
+
.replace(/\.+/g, '.')
|
|
645
|
+
.substring(0, 30);
|
|
646
|
+
|
|
647
|
+
if (username) {
|
|
648
|
+
return username;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Si hay credsStore pero no encontramos username, intentar con docker info
|
|
656
|
+
if (hasCredsStore) {
|
|
657
|
+
try {
|
|
658
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
659
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
660
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
661
|
+
let username = usernameMatch[1].trim();
|
|
662
|
+
|
|
663
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
664
|
+
if (username.includes('@')) {
|
|
665
|
+
username = username.split('@')[0];
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
// Sanitizar el username para Docker Hub
|
|
669
|
+
username = username.toLowerCase()
|
|
670
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
671
|
+
.replace(/^-+|-+$/g, '')
|
|
672
|
+
.replace(/-+/g, '-')
|
|
673
|
+
.replace(/\.+/g, '.')
|
|
674
|
+
.substring(0, 30);
|
|
675
|
+
|
|
676
|
+
if (username) {
|
|
677
|
+
return username;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
} catch (infoError) {
|
|
681
|
+
// Continuar con el error
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Si llegamos aquí, no encontramos el username - solicitar por teclado
|
|
686
|
+
console.log(chalk.yellow('\n⚠️ Could not automatically detect Docker Hub username.'));
|
|
687
|
+
console.log(chalk.gray(' Please enter your Docker Hub username manually.\n'));
|
|
688
|
+
|
|
689
|
+
const answer = await inquirer.prompt([
|
|
690
|
+
{
|
|
691
|
+
type: 'input',
|
|
692
|
+
name: 'username',
|
|
693
|
+
message: 'Docker Hub username:',
|
|
694
|
+
validate: (input: string) => {
|
|
695
|
+
if (!input || input.trim().length === 0) {
|
|
696
|
+
return 'Username is required';
|
|
697
|
+
}
|
|
698
|
+
// Validar formato básico de username Docker Hub
|
|
699
|
+
const sanitized = input.toLowerCase().replace(/[^a-z0-9._-]/g, '');
|
|
700
|
+
if (sanitized !== input.toLowerCase()) {
|
|
701
|
+
return 'Username can only contain lowercase letters, numbers, dots, hyphens, and underscores';
|
|
702
|
+
}
|
|
703
|
+
if (input.length > 30) {
|
|
704
|
+
return 'Username must be 30 characters or less';
|
|
705
|
+
}
|
|
706
|
+
return true;
|
|
707
|
+
},
|
|
708
|
+
filter: (input: string) => {
|
|
709
|
+
// Si el input es un email, extraer solo la parte antes del @
|
|
710
|
+
if (input.includes('@')) {
|
|
711
|
+
return input.split('@')[0].trim();
|
|
712
|
+
}
|
|
713
|
+
return input.trim();
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
]);
|
|
717
|
+
|
|
718
|
+
let username = answer.username.toLowerCase();
|
|
719
|
+
|
|
720
|
+
// Sanitizar el username para Docker Hub
|
|
721
|
+
username = username
|
|
722
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
723
|
+
.replace(/^-+|-+$/g, '')
|
|
724
|
+
.replace(/-+/g, '-')
|
|
725
|
+
.replace(/\.+/g, '.')
|
|
726
|
+
.substring(0, 30);
|
|
727
|
+
|
|
728
|
+
if (!username) {
|
|
729
|
+
throw new Error('Invalid username provided');
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
return username;
|
|
733
|
+
} catch (error: any) {
|
|
734
|
+
// Si el error ya tiene mensaje, relanzarlo
|
|
735
|
+
if (error.message && (error.message.includes('Docker') || error.message.includes('username'))) {
|
|
736
|
+
throw error;
|
|
737
|
+
}
|
|
738
|
+
// Si hay error leyendo Docker config, lanzar error
|
|
739
|
+
throw new Error(
|
|
740
|
+
`Failed to read Docker config: ${error.message || String(error)}\n` +
|
|
741
|
+
' Please ensure you are logged in to Docker: docker login'
|
|
742
|
+
);
|
|
743
|
+
}
|
|
744
|
+
}
|
|
745
|
+
|
|
565
746
|
// Función para leer certificados Docker desde token.json
|
|
566
747
|
function loadDockerCertificatesFromToken(): { caPem: string; certPem: string; keyPem: string; certPath: string } {
|
|
567
748
|
const tokenFilePath = path.join(os.homedir(), '.codecrypto', 'token.json');
|
package/src/commands/deploy.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
3
|
import ora from 'ora';
|
|
4
|
+
import inquirer from 'inquirer';
|
|
4
5
|
import { execSync, spawn } from 'child_process';
|
|
5
6
|
import * as fs from 'fs';
|
|
6
7
|
import * as path from 'path';
|
|
@@ -134,7 +135,9 @@ export const deployCommand = new Command('deploy')
|
|
|
134
135
|
projectName = path.basename(resolvedProjectPath).toLowerCase().replace(/[^a-z0-9._-]/g, '-');
|
|
135
136
|
}
|
|
136
137
|
|
|
137
|
-
|
|
138
|
+
// Obtener el prefijo de imagen desde Docker config o solicitar por teclado
|
|
139
|
+
const dockerHubUsername = await getDockerHubUsernameFromToken();
|
|
140
|
+
const imageBase = `${dockerHubUsername}/${projectName}`;
|
|
138
141
|
const imageName = `${imageBase}:${version}`;
|
|
139
142
|
const imageLatest = `${imageBase}:latest`;
|
|
140
143
|
|
|
@@ -700,6 +703,184 @@ CMD ${JSON.stringify(startCmd)}
|
|
|
700
703
|
}
|
|
701
704
|
});
|
|
702
705
|
|
|
706
|
+
// Función para obtener el username de Docker Hub desde Docker config o solicitar por teclado
|
|
707
|
+
async function getDockerHubUsernameFromToken(): Promise<string> {
|
|
708
|
+
// Obtener el username desde Docker config (requerido para poder hacer push)
|
|
709
|
+
const dockerConfigPath = path.join(os.homedir(), '.docker', 'config.json');
|
|
710
|
+
|
|
711
|
+
if (!fs.existsSync(dockerConfigPath)) {
|
|
712
|
+
throw new Error(
|
|
713
|
+
'Docker authentication not found. Please login to Docker first.\n' +
|
|
714
|
+
' Run: docker login\n' +
|
|
715
|
+
' This is required to push images to Docker Hub.'
|
|
716
|
+
);
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
try {
|
|
720
|
+
const dockerConfig = JSON.parse(fs.readFileSync(dockerConfigPath, 'utf-8'));
|
|
721
|
+
|
|
722
|
+
// Verificar si hay credsStore (las credenciales están en el keychain del sistema)
|
|
723
|
+
const hasCredsStore = dockerConfig.credsStore && dockerConfig.credsStore !== '';
|
|
724
|
+
|
|
725
|
+
// Buscar username en Docker Hub auth
|
|
726
|
+
let dockerHubKeys: string[] = [];
|
|
727
|
+
if (dockerConfig.auths && Object.keys(dockerConfig.auths).length > 0) {
|
|
728
|
+
dockerHubKeys = Object.keys(dockerConfig.auths).filter(reg =>
|
|
729
|
+
reg.includes('docker.io') ||
|
|
730
|
+
reg.includes('hub.docker.com') ||
|
|
731
|
+
reg === 'https://index.docker.io/v1/'
|
|
732
|
+
);
|
|
733
|
+
|
|
734
|
+
// Si hay credsStore, los auths pueden estar vacíos pero las credenciales están en el keychain
|
|
735
|
+
if (hasCredsStore && dockerHubKeys.length > 0) {
|
|
736
|
+
// Intentar obtener username desde docker info
|
|
737
|
+
try {
|
|
738
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
739
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
740
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
741
|
+
let username = usernameMatch[1].trim();
|
|
742
|
+
|
|
743
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
744
|
+
if (username.includes('@')) {
|
|
745
|
+
username = username.split('@')[0];
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
// Sanitizar el username para Docker Hub
|
|
749
|
+
username = username.toLowerCase()
|
|
750
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
751
|
+
.replace(/^-+|-+$/g, '')
|
|
752
|
+
.replace(/-+/g, '-')
|
|
753
|
+
.replace(/\.+/g, '.')
|
|
754
|
+
.substring(0, 30);
|
|
755
|
+
|
|
756
|
+
if (username) {
|
|
757
|
+
return username;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
} catch (infoError) {
|
|
761
|
+
// Si docker info falla, continuar con otros métodos
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Si no hay credsStore, buscar username directamente en auths
|
|
766
|
+
if (!hasCredsStore) {
|
|
767
|
+
for (const key of dockerHubKeys) {
|
|
768
|
+
const authData = dockerConfig.auths[key];
|
|
769
|
+
if (authData && authData.username) {
|
|
770
|
+
let username = authData.username;
|
|
771
|
+
|
|
772
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
773
|
+
if (username.includes('@')) {
|
|
774
|
+
username = username.split('@')[0];
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
// Sanitizar el username para Docker Hub
|
|
778
|
+
username = username.toLowerCase()
|
|
779
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
780
|
+
.replace(/^-+|-+$/g, '')
|
|
781
|
+
.replace(/-+/g, '-')
|
|
782
|
+
.replace(/\.+/g, '.')
|
|
783
|
+
.substring(0, 30);
|
|
784
|
+
|
|
785
|
+
if (username) {
|
|
786
|
+
return username;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
// Si hay credsStore pero no encontramos username, intentar con docker info
|
|
794
|
+
if (hasCredsStore) {
|
|
795
|
+
try {
|
|
796
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
797
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
798
|
+
if (usernameMatch && usernameMatch[1]) {
|
|
799
|
+
let username = usernameMatch[1].trim();
|
|
800
|
+
|
|
801
|
+
// Si el username es un email, extraer solo la parte antes del @
|
|
802
|
+
if (username.includes('@')) {
|
|
803
|
+
username = username.split('@')[0];
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
// Sanitizar el username para Docker Hub
|
|
807
|
+
username = username.toLowerCase()
|
|
808
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
809
|
+
.replace(/^-+|-+$/g, '')
|
|
810
|
+
.replace(/-+/g, '-')
|
|
811
|
+
.replace(/\.+/g, '.')
|
|
812
|
+
.substring(0, 30);
|
|
813
|
+
|
|
814
|
+
if (username) {
|
|
815
|
+
return username;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
} catch (infoError) {
|
|
819
|
+
// Continuar con el error
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// Si llegamos aquí, no encontramos el username - solicitar por teclado
|
|
824
|
+
console.log(chalk.yellow('\n⚠️ Could not automatically detect Docker Hub username.'));
|
|
825
|
+
console.log(chalk.gray(' Please enter your Docker Hub username manually.\n'));
|
|
826
|
+
|
|
827
|
+
const answer = await inquirer.prompt([
|
|
828
|
+
{
|
|
829
|
+
type: 'input',
|
|
830
|
+
name: 'username',
|
|
831
|
+
message: 'Docker Hub username:',
|
|
832
|
+
validate: (input: string) => {
|
|
833
|
+
if (!input || input.trim().length === 0) {
|
|
834
|
+
return 'Username is required';
|
|
835
|
+
}
|
|
836
|
+
// Validar formato básico de username Docker Hub
|
|
837
|
+
const sanitized = input.toLowerCase().replace(/[^a-z0-9._-]/g, '');
|
|
838
|
+
if (sanitized !== input.toLowerCase()) {
|
|
839
|
+
return 'Username can only contain lowercase letters, numbers, dots, hyphens, and underscores';
|
|
840
|
+
}
|
|
841
|
+
if (input.length > 30) {
|
|
842
|
+
return 'Username must be 30 characters or less';
|
|
843
|
+
}
|
|
844
|
+
return true;
|
|
845
|
+
},
|
|
846
|
+
filter: (input: string) => {
|
|
847
|
+
// Si el input es un email, extraer solo la parte antes del @
|
|
848
|
+
if (input.includes('@')) {
|
|
849
|
+
return input.split('@')[0].trim();
|
|
850
|
+
}
|
|
851
|
+
return input.trim();
|
|
852
|
+
}
|
|
853
|
+
}
|
|
854
|
+
]);
|
|
855
|
+
|
|
856
|
+
let username = answer.username.toLowerCase();
|
|
857
|
+
|
|
858
|
+
// Sanitizar el username para Docker Hub
|
|
859
|
+
username = username
|
|
860
|
+
.replace(/[^a-z0-9._-]/g, '-')
|
|
861
|
+
.replace(/^-+|-+$/g, '')
|
|
862
|
+
.replace(/-+/g, '-')
|
|
863
|
+
.replace(/\.+/g, '.')
|
|
864
|
+
.substring(0, 30);
|
|
865
|
+
|
|
866
|
+
if (!username) {
|
|
867
|
+
throw new Error('Invalid username provided');
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
return username;
|
|
871
|
+
} catch (error: any) {
|
|
872
|
+
// Si el error ya tiene mensaje, relanzarlo
|
|
873
|
+
if (error.message && (error.message.includes('Docker') || error.message.includes('username'))) {
|
|
874
|
+
throw error;
|
|
875
|
+
}
|
|
876
|
+
// Si hay error leyendo Docker config, lanzar error
|
|
877
|
+
throw new Error(
|
|
878
|
+
`Failed to read Docker config: ${error.message || String(error)}\n` +
|
|
879
|
+
' Please ensure you are logged in to Docker: docker login'
|
|
880
|
+
);
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
|
|
703
884
|
// Función para leer certificados Docker desde token.json
|
|
704
885
|
function loadDockerCertificatesFromToken(): { caPem: string; certPem: string; keyPem: string; certPath: string } {
|
|
705
886
|
const tokenFilePath = path.join(os.homedir(), '.codecrypto', 'token.json');
|
package/src/commands/doctor.ts
CHANGED
|
@@ -127,23 +127,210 @@ export const doctorCommand = new Command('doctor')
|
|
|
127
127
|
});
|
|
128
128
|
}
|
|
129
129
|
|
|
130
|
-
// 6. Check Docker
|
|
131
|
-
const dockerAuthCheck = ora('Checking Docker
|
|
130
|
+
// 6. Check Docker authentication
|
|
131
|
+
const dockerAuthCheck = ora('Checking Docker authentication...').start();
|
|
132
132
|
try {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
// Obtener email del token.json para comparar
|
|
134
|
+
const tokenFilePath = path.join(os.homedir(), '.codecrypto', 'token.json');
|
|
135
|
+
let tokenEmail: string | null = null;
|
|
136
|
+
if (fs.existsSync(tokenFilePath)) {
|
|
137
|
+
try {
|
|
138
|
+
const tokenData = JSON.parse(fs.readFileSync(tokenFilePath, 'utf-8'));
|
|
139
|
+
tokenEmail = tokenData.email || null;
|
|
140
|
+
} catch {
|
|
141
|
+
// Ignorar errores al leer token
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Verificar si hay credenciales guardadas en Docker config
|
|
146
|
+
const dockerConfigPath = path.join(os.homedir(), '.docker', 'config.json');
|
|
147
|
+
let dockerUsername: string | null = null;
|
|
148
|
+
let dockerEmail: string | null = null;
|
|
149
|
+
let hasDockerAuth = false;
|
|
150
|
+
let dockerAuthInfo = '';
|
|
151
|
+
|
|
152
|
+
if (fs.existsSync(dockerConfigPath)) {
|
|
153
|
+
try {
|
|
154
|
+
const dockerConfig = JSON.parse(fs.readFileSync(dockerConfigPath, 'utf-8'));
|
|
155
|
+
|
|
156
|
+
// Verificar si hay auths configurados
|
|
157
|
+
if (dockerConfig.auths && Object.keys(dockerConfig.auths).length > 0) {
|
|
158
|
+
hasDockerAuth = true;
|
|
159
|
+
const registries = Object.keys(dockerConfig.auths);
|
|
160
|
+
dockerAuthInfo = `Authenticated to: ${registries.join(', ')}`;
|
|
161
|
+
|
|
162
|
+
// Intentar obtener el username de Docker Hub
|
|
163
|
+
const dockerHubKey = registries.find(reg =>
|
|
164
|
+
reg.includes('docker.io') ||
|
|
165
|
+
reg.includes('hub.docker.com') ||
|
|
166
|
+
reg === 'https://index.docker.io/v1/'
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (dockerHubKey && dockerConfig.auths[dockerHubKey]) {
|
|
170
|
+
// El username puede estar en auths[registry].auth (base64) o directamente
|
|
171
|
+
const authData = dockerConfig.auths[dockerHubKey];
|
|
172
|
+
if (authData && authData.username) {
|
|
173
|
+
dockerUsername = authData.username;
|
|
174
|
+
// Si el username parece un email, usarlo como email
|
|
175
|
+
if (dockerUsername && dockerUsername.includes('@')) {
|
|
176
|
+
dockerEmail = dockerUsername;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Intentar obtener username de docker info como fallback
|
|
182
|
+
if (!dockerUsername) {
|
|
183
|
+
try {
|
|
184
|
+
const dockerInfo = execSync('docker info', { encoding: 'utf-8', stdio: 'pipe', timeout: 5000 });
|
|
185
|
+
const usernameMatch = dockerInfo.match(/Username:\s*(.+)/i);
|
|
186
|
+
if (usernameMatch) {
|
|
187
|
+
dockerUsername = usernameMatch[1].trim();
|
|
188
|
+
if (dockerUsername.includes('@')) {
|
|
189
|
+
dockerEmail = dockerUsername;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
} catch {
|
|
193
|
+
// Ignorar errores
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Verificar específicamente Docker Hub
|
|
198
|
+
const hasDockerHub = registries.some(reg =>
|
|
199
|
+
reg.includes('docker.io') ||
|
|
200
|
+
reg.includes('hub.docker.com') ||
|
|
201
|
+
reg === 'https://index.docker.io/v1/'
|
|
202
|
+
);
|
|
203
|
+
|
|
204
|
+
// Construir mensaje con información de email/usuario
|
|
205
|
+
let authMessage = `Docker authentication verified: ${dockerAuthInfo}`;
|
|
206
|
+
if (dockerUsername || dockerEmail) {
|
|
207
|
+
const dockerIdentity = dockerEmail || dockerUsername;
|
|
208
|
+
authMessage += ` (User: ${dockerIdentity})`;
|
|
209
|
+
|
|
210
|
+
// Comparar con token.json
|
|
211
|
+
if (tokenEmail && dockerEmail) {
|
|
212
|
+
if (dockerEmail.toLowerCase() === tokenEmail.toLowerCase()) {
|
|
213
|
+
authMessage += ` ✓ Matches token.json email`;
|
|
214
|
+
} else {
|
|
215
|
+
authMessage += ` ⚠ Different from token.json email (${tokenEmail})`;
|
|
216
|
+
}
|
|
217
|
+
} else if (tokenEmail && dockerUsername && !dockerEmail) {
|
|
218
|
+
// Comparar username con email del token (parte antes del @)
|
|
219
|
+
const tokenUsername = tokenEmail.split('@')[0].toLowerCase();
|
|
220
|
+
if (dockerUsername.toLowerCase() === tokenUsername) {
|
|
221
|
+
authMessage += ` ✓ Username matches token.json email`;
|
|
222
|
+
} else {
|
|
223
|
+
authMessage += ` ⚠ Username differs from token.json email (${tokenEmail})`;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (hasDockerHub) {
|
|
229
|
+
dockerAuthCheck.succeed(`Docker authentication OK (Docker Hub configured)`);
|
|
230
|
+
checks.push({
|
|
231
|
+
name: 'Docker Auth',
|
|
232
|
+
status: 'success',
|
|
233
|
+
message: authMessage
|
|
234
|
+
});
|
|
235
|
+
} else {
|
|
236
|
+
dockerAuthCheck.succeed(`Docker authentication OK (${registries.length} registry/registries configured)`);
|
|
237
|
+
checks.push({
|
|
238
|
+
name: 'Docker Auth',
|
|
239
|
+
status: 'success',
|
|
240
|
+
message: authMessage
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
} else {
|
|
244
|
+
// No hay auths configurados, intentar verificar con pull
|
|
245
|
+
try {
|
|
246
|
+
execSync('docker pull hello-world:latest', { encoding: 'utf-8', stdio: 'pipe', timeout: 10000 });
|
|
247
|
+
dockerAuthCheck.succeed('Docker authentication OK (public access)');
|
|
248
|
+
let message = 'Docker can access public images (authentication may not be required)';
|
|
249
|
+
if (tokenEmail) {
|
|
250
|
+
message += ` (Token email: ${tokenEmail})`;
|
|
251
|
+
}
|
|
252
|
+
checks.push({
|
|
253
|
+
name: 'Docker Auth',
|
|
254
|
+
status: 'success',
|
|
255
|
+
message: message
|
|
256
|
+
});
|
|
257
|
+
} catch (pullError) {
|
|
258
|
+
dockerAuthCheck.warn('Docker authentication not configured');
|
|
259
|
+
let details = 'Run "docker login" if you need to push images to Docker Hub or private registries';
|
|
260
|
+
if (tokenEmail) {
|
|
261
|
+
details += ` (Token email: ${tokenEmail})`;
|
|
262
|
+
}
|
|
263
|
+
checks.push({
|
|
264
|
+
name: 'Docker Auth',
|
|
265
|
+
status: 'warning',
|
|
266
|
+
message: 'Docker authentication not configured',
|
|
267
|
+
details: details
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
} catch (configError) {
|
|
272
|
+
// Error leyendo config, intentar verificar con pull
|
|
273
|
+
try {
|
|
274
|
+
execSync('docker pull hello-world:latest', { encoding: 'utf-8', stdio: 'pipe', timeout: 10000 });
|
|
275
|
+
dockerAuthCheck.succeed('Docker authentication OK');
|
|
276
|
+
let message = 'Docker can access public images';
|
|
277
|
+
if (tokenEmail) {
|
|
278
|
+
message += ` (Token email: ${tokenEmail})`;
|
|
279
|
+
}
|
|
280
|
+
checks.push({
|
|
281
|
+
name: 'Docker Auth',
|
|
282
|
+
status: 'success',
|
|
283
|
+
message: message
|
|
284
|
+
});
|
|
285
|
+
} catch (pullError) {
|
|
286
|
+
dockerAuthCheck.warn('Docker authentication may be required');
|
|
287
|
+
let details = 'Run "docker login" if you need to push images';
|
|
288
|
+
if (tokenEmail) {
|
|
289
|
+
details += ` (Token email: ${tokenEmail})`;
|
|
290
|
+
}
|
|
291
|
+
checks.push({
|
|
292
|
+
name: 'Docker Auth',
|
|
293
|
+
status: 'warning',
|
|
294
|
+
message: 'Docker authentication not verified',
|
|
295
|
+
details: details
|
|
296
|
+
});
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
} else {
|
|
300
|
+
// No existe config.json, intentar verificar con pull
|
|
301
|
+
try {
|
|
302
|
+
execSync('docker pull hello-world:latest', { encoding: 'utf-8', stdio: 'pipe', timeout: 10000 });
|
|
303
|
+
dockerAuthCheck.succeed('Docker authentication OK (public access)');
|
|
304
|
+
let message = 'Docker can access public images (authentication may not be required)';
|
|
305
|
+
if (tokenEmail) {
|
|
306
|
+
message += ` (Token email: ${tokenEmail})`;
|
|
307
|
+
}
|
|
308
|
+
checks.push({
|
|
309
|
+
name: 'Docker Auth',
|
|
310
|
+
status: 'success',
|
|
311
|
+
message: message
|
|
312
|
+
});
|
|
313
|
+
} catch (error) {
|
|
314
|
+
dockerAuthCheck.warn('Docker authentication not configured');
|
|
315
|
+
let details = 'Run "docker login" if you need to push images to Docker Hub or private registries';
|
|
316
|
+
if (tokenEmail) {
|
|
317
|
+
details += ` (Token email: ${tokenEmail})`;
|
|
318
|
+
}
|
|
319
|
+
checks.push({
|
|
320
|
+
name: 'Docker Auth',
|
|
321
|
+
status: 'warning',
|
|
322
|
+
message: 'Docker authentication not configured',
|
|
323
|
+
details: details
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
} catch (error: any) {
|
|
328
|
+
dockerAuthCheck.fail('Docker authentication check failed');
|
|
142
329
|
checks.push({
|
|
143
|
-
name: 'Docker
|
|
144
|
-
status: '
|
|
145
|
-
message: 'Docker
|
|
146
|
-
details:
|
|
330
|
+
name: 'Docker Auth',
|
|
331
|
+
status: 'error',
|
|
332
|
+
message: 'Docker authentication check failed',
|
|
333
|
+
details: `Error: ${error.message || String(error)}`
|
|
147
334
|
});
|
|
148
335
|
}
|
|
149
336
|
|
|
@@ -499,11 +686,11 @@ export const doctorCommand = new Command('doctor')
|
|
|
499
686
|
}
|
|
500
687
|
|
|
501
688
|
besu1Check.succeed(`Besu1 network accessible (chain-id: ${chainId}, block: ${blockNumber})`);
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
689
|
+
checks.push({
|
|
690
|
+
name: 'Besu1 Network',
|
|
691
|
+
status: 'success',
|
|
505
692
|
message: `Besu1 network accessible: ${rpcUrl} (chain-id: ${chainId}, block: ${blockNumber})`
|
|
506
|
-
|
|
693
|
+
});
|
|
507
694
|
}
|
|
508
695
|
} catch (error: any) {
|
|
509
696
|
const errorMsg = error.message || String(error);
|