• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

square / keywhiz / 3963561994

pending completion
3963561994

Pull #1189

github

GitHub
Merge 0e51f2a1d into c1e040c06
Pull Request #1189: Adding CLI option to the "describe secrets" action to include deleted secrets

33 of 33 new or added lines in 4 files covered. (100.0%)

5238 of 6959 relevant lines covered (75.27%)

0.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.54
/cli/src/main/java/keywhiz/cli/Printing.java
1
/*
2
 * Copyright (C) 2015 Square, Inc.
3
 *
4
 * Licensed under the Apache License, Version 2.0 (the "License");
5
 * you may not use this file except in compliance with the License.
6
 * You may obtain a copy of the License at
7
 *
8
 *      http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 * Unless required by applicable law or agreed to in writing, software
11
 * distributed under the License is distributed on an "AS IS" BASIS,
12
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 * See the License for the specific language governing permissions and
14
 * limitations under the License.
15
 */
16
package keywhiz.cli;
17

18
import com.fasterxml.jackson.core.JsonProcessingException;
19
import com.fasterxml.jackson.databind.ObjectMapper;
20
import com.google.common.base.Strings;
21
import com.google.common.base.Throwables;
22
import java.io.IOException;
23
import java.text.DateFormat;
24
import java.util.Comparator;
25
import java.util.Date;
26
import java.util.List;
27
import java.util.Optional;
28
import javax.inject.Inject;
29
import keywhiz.api.ClientDetailResponse;
30
import keywhiz.api.GroupDetailResponse;
31
import keywhiz.api.SecretDetailResponse;
32
import keywhiz.api.model.Client;
33
import keywhiz.api.model.Group;
34
import keywhiz.api.model.SanitizedSecret;
35
import keywhiz.client.KeywhizClient;
36

37
public class Printing {
38
  private final KeywhizClient keywhizClient;
39

40
  private static final String INDENT = "\t";
41
  private static final String DOUBLE_INDENT = Strings.repeat(INDENT, 2);
1✔
42

43
  @Inject
44
  public Printing(final KeywhizClient keywhizClient) {
×
45
    this.keywhizClient = keywhizClient;
×
46
  }
×
47

48
  public void printClientWithDetails(Client client) {
49
    System.out.println(client.getName());
×
50
    ClientDetailResponse clientDetails;
51
    try {
52
      clientDetails = keywhizClient.clientDetailsForId(client.getId());
×
53
    } catch (IOException e) {
×
54
      throw Throwables.propagate(e);
×
55
    }
×
56

57
    System.out.println(INDENT + "Groups:");
×
58
    clientDetails.groups.stream()
×
59
        .sorted(Comparator.comparing(Group::getName))
×
60
        .forEach(g -> System.out.println(DOUBLE_INDENT + g.getName()));
×
61

62
    System.out.println(INDENT + "Secrets:");
×
63
    clientDetails.secrets.stream()
×
64
        .sorted(Comparator.comparing(SanitizedSecret::name))
×
65
        .forEach(s -> System.out.println(DOUBLE_INDENT + SanitizedSecret.displayName(s)));
×
66

67
    if (clientDetails.lastSeen == null) {
×
68
      System.out.println(INDENT + "Last Seen: never");
×
69
    } else {
70
      Date d = new Date(clientDetails.lastSeen.toEpochSecond() * 1000);
×
71
      System.out.printf(INDENT + "Last Seen: %s%n", DateFormat.getDateTimeInstance().format(d));
×
72
    }
73

74
    if (!clientDetails.description.isEmpty()) {
×
75
      System.out.println(INDENT + "Description:");
×
76
      System.out.println(DOUBLE_INDENT + clientDetails.description);
×
77
    }
78

79
    if (clientDetails.spiffeId != null && !clientDetails.spiffeId.isEmpty()) {
×
80
      System.out.println(INDENT + "Spiffe ID:");
×
81
      System.out.println(DOUBLE_INDENT + clientDetails.spiffeId);
×
82
    }
83

84
    if (!clientDetails.createdBy.isEmpty()) {
×
85
      System.out.println(INDENT + "Created by:");
×
86
      System.out.println(DOUBLE_INDENT + clientDetails.createdBy);
×
87
    }
88

89
    System.out.println(INDENT + "Created at:");
×
90
    Date d = new Date(clientDetails.creationDate.toEpochSecond() * 1000);
×
91
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
92

93
    if (!clientDetails.updatedBy.isEmpty()) {
×
94
      System.out.println(INDENT + "Updated by:");
×
95
      System.out.println(DOUBLE_INDENT + clientDetails.updatedBy);
×
96
    }
97

98
    System.out.println(INDENT + "Updated at:");
×
99
    d = new Date(clientDetails.updateDate.toEpochSecond() * 1000);
×
100
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
101
  }
×
102

103
  public void printGroupWithDetails(Group group) {
104
    System.out.println(group.getName());
×
105
    GroupDetailResponse groupDetails;
106
    try {
107
      groupDetails = keywhizClient.groupDetailsForId(group.getId());
×
108
    } catch (IOException e) {
×
109
      throw Throwables.propagate(e);
×
110
    }
×
111

112
    System.out.println(INDENT + "Clients:");
×
113
    groupDetails.getClients().stream()
×
114
        .sorted(Comparator.comparing(Client::getName))
×
115
        .forEach(c -> System.out.println(DOUBLE_INDENT + c.getName()));
×
116

117
    System.out.println(INDENT + "Secrets:");
×
118
    groupDetails.getSecrets().stream()
×
119
        .sorted(Comparator.comparing(SanitizedSecret::name))
×
120
        .forEach(s -> System.out.println(DOUBLE_INDENT + SanitizedSecret.displayName(s)));
×
121

122
    System.out.println(INDENT + "Metadata:");
×
123
    if (!groupDetails.getMetadata().isEmpty()) {
×
124
      String metadata;
125
      try {
126
        metadata = new ObjectMapper().writeValueAsString(groupDetails.getMetadata());
×
127
      } catch (JsonProcessingException e) {
×
128
        throw Throwables.propagate(e);
×
129
      }
×
130
      System.out.println(DOUBLE_INDENT + metadata);
×
131
    }
132

133
    if (!groupDetails.getDescription().isEmpty()) {
×
134
      System.out.println(INDENT + "Description:");
×
135
      System.out.println(DOUBLE_INDENT + groupDetails.getDescription());
×
136
    }
137

138
    if (!groupDetails.getCreatedBy().isEmpty()) {
×
139
      System.out.println(INDENT + "Created by:");
×
140
      System.out.println(DOUBLE_INDENT + groupDetails.getCreatedBy());
×
141
    }
142

143
    System.out.println(INDENT + "Created at:");
×
144
    Date d = new Date(groupDetails.getCreationDate().toEpochSecond() * 1000);
×
145
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
146

147
    if (!groupDetails.getUpdatedBy().isEmpty()) {
×
148
      System.out.println(INDENT + "Updated by:");
×
149
      System.out.println(DOUBLE_INDENT + groupDetails.getUpdatedBy());
×
150
    }
151

152
    System.out.println(INDENT + "Updated at:");
×
153
    d = new Date(groupDetails.getUpdateDate().toEpochSecond() * 1000);
×
154
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
155
  }
×
156

157
  public void printDeletedSecretsWithDetails(List<SanitizedSecret> deletedSecrets) {
158
    System.out.println("Deleted Secrets:");
×
159
    if (deletedSecrets.isEmpty()) {
×
160
      System.out.println("None found");
×
161
    } else {
162
      deletedSecrets.forEach(this::printSanitizedSecretWithDetails);
×
163
    }
164
  }
×
165

166
  public void printSanitizedSecretWithDetails(SanitizedSecret secret) {
167
    System.out.println(SanitizedSecret.displayName(secret));
×
168
    SecretDetailResponse secretDetails;
169
    try {
170
      secretDetails = keywhizClient.secretDetailsForId(secret.id());
×
171
    } catch (IOException e) {
×
172
      throw Throwables.propagate(e);
×
173
    }
×
174

175
    System.out.println(INDENT + "Internal Identifier:");
×
176
    System.out.println(DOUBLE_INDENT + secret.id());
×
177

178
    System.out.println(INDENT + "Owner:");
×
179
    if (secret.owner() != null) {
×
180
      System.out.println(DOUBLE_INDENT + secret.owner());
×
181
    }
182

183
    System.out.println(INDENT + "Groups:");
×
184
    secretDetails.groups.stream()
×
185
        .sorted(Comparator.comparing(Group::getName))
×
186
        .forEach(g -> System.out.println(DOUBLE_INDENT + g.getName()));
×
187

188
    System.out.println(INDENT + "Clients:");
×
189
    secretDetails.clients.stream()
×
190
        .sorted(Comparator.comparing(Client::getName))
×
191
        .forEach(c -> System.out.println(DOUBLE_INDENT + c.getName()));
×
192

193
    System.out.println(INDENT + "Content HMAC:");
×
194
    if (secret.checksum().isEmpty()) {
×
195
      System.out.println(DOUBLE_INDENT + "WARNING: Content HMAC not calculated!");
×
196
    } else {
197
      System.out.println(DOUBLE_INDENT + secret.checksum());
×
198
    }
199

200
    System.out.println(INDENT + "Metadata:");
×
201
    if (!secret.metadata().isEmpty()) {
×
202
      String metadata;
203
      try {
204
        metadata = new ObjectMapper().writeValueAsString(secret.metadata());
×
205
      } catch (JsonProcessingException e) {
×
206
        throw Throwables.propagate(e);
×
207
      }
×
208
      System.out.println(DOUBLE_INDENT + metadata);
×
209
    }
210

211
    if (secret.expiry() > 0) {
×
212
      System.out.println(INDENT + "Expiry:");
×
213
      Date d = new Date(secret.expiry() * 1000);
×
214
      System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
215
    }
216

217
    if (!secret.description().isEmpty()) {
×
218
      System.out.println(INDENT + "Description:");
×
219
      System.out.println(DOUBLE_INDENT + secret.description());
×
220
    }
221

222
    if (!secret.createdBy().isEmpty()) {
×
223
      System.out.println(INDENT + "Created by:");
×
224
      System.out.println(DOUBLE_INDENT + secret.createdBy());
×
225
    }
226

227
    System.out.println(INDENT + "Created at:");
×
228
    Date d = new Date(secret.createdAt().toEpochSecond() * 1000);
×
229
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
230

231
    if (!secret.updatedBy().isEmpty()) {
×
232
      System.out.println(INDENT + "Updated by:");
×
233
      System.out.println(DOUBLE_INDENT + secret.updatedBy());
×
234
    }
235

236
    System.out.println(INDENT + "Updated at:");
×
237
    d = new Date(secret.updatedAt().toEpochSecond() * 1000);
×
238
    System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
239

240
    if (!secret.contentCreatedBy().isEmpty()) {
×
241
      System.out.println(INDENT + "Content created by:");
×
242
      System.out.println(DOUBLE_INDENT + secret.contentCreatedBy());
×
243
    }
244

245
    if (secret.contentCreatedAt().isPresent()) {
×
246
      System.out.println(INDENT + "Content created at:");
×
247
      d = new Date(secret.contentCreatedAt().get().toEpochSecond() * 1000);
×
248
      System.out.println(DOUBLE_INDENT + DateFormat.getDateTimeInstance().format(d));
×
249
    }
250
  }
×
251

252
  public void printAllClients(List<Client> clients) {
253
    clients.stream()
×
254
        .sorted(Comparator.comparing(Client::getName))
×
255
        .forEach(c -> System.out.println(c.getName()));
×
256
  }
×
257

258
  public void printAllGroups(List<Group> groups) {
259
    groups.stream()
×
260
        .sorted(Comparator.comparing(Group::getName))
×
261
        .forEach(g -> System.out.println(g.getName()));
×
262
  }
×
263

264
  public void printAllSanitizedSecrets(List<SanitizedSecret> secrets) {
265
    secrets.stream()
×
266
        .sorted(Comparator.comparing(SanitizedSecret::name))
×
267
        .forEach(s -> System.out.println(SanitizedSecret.displayName(s)));
×
268
  }
×
269

270
  public void printSecretVersions(List<SanitizedSecret> versions, Optional<Long> currentVersion) {
271
    if (versions.isEmpty()) {
×
272
      return;
×
273
    }
274

275
    System.out.println(versions.get(0).name() + '\n');
×
276

277
    if (currentVersion.isEmpty()) {
×
278
      System.out.println("Current secret version unknown!");
×
279
    }
280

281
    for (SanitizedSecret secret : versions) {
×
282
      if (secret.version().isPresent()) {
×
283
        if (currentVersion.isPresent() && secret.version().get().equals(currentVersion.get())) {
×
284
          System.out.println(
×
285
              String.format("*** Current secret version id: %d ***", secret.version().get()));
×
286
        } else {
287
          System.out.println(String.format("Version id for rollback: %d", secret.version().get()));
×
288
        }
289
      } else {
290
        System.out.println("Version id for rollback: Unknown!");
×
291
      }
292

293
      if (secret.contentCreatedAt().isPresent()) {
×
294
        if (secret.contentCreatedBy().isEmpty()) {
×
295
          System.out.println(INDENT + String.format("Created on %s (creator unknown)",
×
296
              DateFormat.getDateTimeInstance()
×
297
                  .format(new Date(secret.contentCreatedAt().get().toEpochSecond() * 1000))));
×
298
        } else {
299
          System.out.println(
×
300
              INDENT + String.format("Created by %s on %s", secret.contentCreatedBy(),
×
301
                  DateFormat.getDateTimeInstance()
×
302
                      .format(new Date(secret.contentCreatedAt().get().toEpochSecond() * 1000))));
×
303
        }
304
      } else {
305
        if (secret.contentCreatedBy().isEmpty()) {
×
306
          System.out.println(INDENT + "Creator and creation date unknown");
×
307
        } else {
308
          System.out.println(
×
309
              INDENT + String.format("Created by %s (date unknown)", secret.contentCreatedBy()));
×
310
        }
311
      }
312

313
      if (secret.expiry() == 0) {
×
314
        System.out.println(INDENT + "Does not expire");
×
315
      } else {
316
        System.out.println(INDENT + String.format("Expires on %s", DateFormat.getDateTimeInstance()
×
317
            .format(new Date(secret.expiry() * 1000))));
×
318
      }
319

320
      if (!secret.metadata().isEmpty()) {
×
321
        System.out.println(INDENT + String.format("Metadata: %s", secret.metadata()));
×
322
      }
323

324
      if (!secret.checksum().isEmpty()) {
×
325
        System.out.println(INDENT + String.format("Content HMAC: %s", secret.checksum()));
×
326
      }
327
      System.out.print("\n"); // Add space between the versions
×
328
    }
×
329
  }
×
330
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc